aboutsummaryrefslogtreecommitdiff
path: root/src/libutil
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2023-01-25 17:31:27 +0100
committerEelco Dolstra <edolstra@gmail.com>2023-02-07 22:51:53 +0100
commitfb2f7f5dcc6b37a4f39f59d9f477d3fa57d79095 (patch)
treedfe12a07aa527267b338023c537b1efa07272982 /src/libutil
parent1ba13b17db1d2ff4342b41cbd610b76060582335 (diff)
Fix auto-uid-allocation in Docker containers
This didn't work because sandboxing doesn't work in Docker. However, the sandboxing check is done lazily - after clone(CLONE_NEWNS) fails, we retry with sandboxing disabled. But at that point, we've already done UID allocation under the assumption that user namespaces are enabled. So let's get rid of the "goto fallback" logic and just detect early whether user / mount namespaces are enabled. This commit also gets rid of a compatibility hack for some ancient Linux kernels (<2.13).
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/namespaces.cc63
-rw-r--r--src/libutil/namespaces.hh9
2 files changed, 72 insertions, 0 deletions
diff --git a/src/libutil/namespaces.cc b/src/libutil/namespaces.cc
new file mode 100644
index 000000000..0c3c3cbdd
--- /dev/null
+++ b/src/libutil/namespaces.cc
@@ -0,0 +1,63 @@
+#include "namespaces.hh"
+#include "util.hh"
+
+#if __linux__
+
+namespace nix {
+
+bool userNamespacesSupported()
+{
+ static bool res = [&]() -> bool
+ {
+ if (!pathExists("/proc/self/ns/user")) {
+ notice("'/proc/self/ns/user' does not exist; your kernel was likely built without CONFIG_USER_NS=y, which is required for sandboxing");
+ return false;
+ }
+
+ Path maxUserNamespaces = "/proc/sys/user/max_user_namespaces";
+ if (!pathExists(maxUserNamespaces) ||
+ trim(readFile(maxUserNamespaces)) == "0")
+ {
+ notice("user namespaces appear to be disabled; they are required for sandboxing; check '/proc/sys/user/max_user_namespaces'");
+ return false;
+ }
+
+ Path procSysKernelUnprivilegedUsernsClone = "/proc/sys/kernel/unprivileged_userns_clone";
+ if (pathExists(procSysKernelUnprivilegedUsernsClone)
+ && trim(readFile(procSysKernelUnprivilegedUsernsClone)) == "0")
+ {
+ notice("user namespaces appear to be disabled; they are required for sandboxing; check '/proc/sys/kernel/unprivileged_userns_clone'");
+ return false;
+ }
+
+ Pid pid = startProcess([&]()
+ {
+ auto res = unshare(CLONE_NEWUSER);
+ _exit(res ? 1 : 0);
+ });
+
+ return pid.wait() == 0;
+ }();
+ return res;
+}
+
+bool mountNamespacesSupported()
+{
+ static bool res = [&]() -> bool
+ {
+ bool useUserNamespace = userNamespacesSupported();
+
+ Pid pid = startProcess([&]()
+ {
+ auto res = unshare(CLONE_NEWNS | (useUserNamespace ? CLONE_NEWUSER : 0));
+ _exit(res ? 1 : 0);
+ });
+
+ return pid.wait() == 0;
+ }();
+ return res;
+}
+
+}
+
+#endif
diff --git a/src/libutil/namespaces.hh b/src/libutil/namespaces.hh
new file mode 100644
index 000000000..4ed6cb683
--- /dev/null
+++ b/src/libutil/namespaces.hh
@@ -0,0 +1,9 @@
+#pragma once
+
+namespace nix {
+
+bool userNamespacesSupported();
+
+bool mountNamespacesSupported();
+
+}