aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/namespaces.cc
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2023-02-07 23:35:39 +0100
committerGitHub <noreply@github.com>2023-02-07 23:35:39 +0100
commitae6de012eefb6fe37cd2eb1e6abc40c3fd62d6f9 (patch)
tree3a8a25fd3667942c58ac22cbae09afb978ee1471 /src/libutil/namespaces.cc
parent9aeaf98c4b0e99a3af45517a2a54f7715a396542 (diff)
parent0a70b411e1afaa22d8b01560de908246042daf10 (diff)
Merge pull request #7692 from edolstra/fix-docker-auto-uid-allocation
Fix auto-uid-allocation in Docker containers
Diffstat (limited to 'src/libutil/namespaces.cc')
-rw-r--r--src/libutil/namespaces.cc100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/libutil/namespaces.cc b/src/libutil/namespaces.cc
new file mode 100644
index 000000000..fdd52d92b
--- /dev/null
+++ b/src/libutil/namespaces.cc
@@ -0,0 +1,100 @@
+#if __linux__
+
+#include "namespaces.hh"
+#include "util.hh"
+#include "finally.hh"
+
+#include <mntent.h>
+
+namespace nix {
+
+bool userNamespacesSupported()
+{
+ static auto res = [&]() -> bool
+ {
+ if (!pathExists("/proc/self/ns/user")) {
+ debug("'/proc/self/ns/user' does not exist; your kernel was likely built without CONFIG_USER_NS=y");
+ return false;
+ }
+
+ Path maxUserNamespaces = "/proc/sys/user/max_user_namespaces";
+ if (!pathExists(maxUserNamespaces) ||
+ trim(readFile(maxUserNamespaces)) == "0")
+ {
+ debug("user namespaces appear to be disabled; check '/proc/sys/user/max_user_namespaces'");
+ return false;
+ }
+
+ Path procSysKernelUnprivilegedUsernsClone = "/proc/sys/kernel/unprivileged_userns_clone";
+ if (pathExists(procSysKernelUnprivilegedUsernsClone)
+ && trim(readFile(procSysKernelUnprivilegedUsernsClone)) == "0")
+ {
+ debug("user namespaces appear to be disabled; check '/proc/sys/kernel/unprivileged_userns_clone'");
+ return false;
+ }
+
+ Pid pid = startProcess([&]()
+ {
+ auto res = unshare(CLONE_NEWUSER);
+ _exit(res ? 1 : 0);
+ });
+
+ bool supported = pid.wait() == 0;
+
+ if (!supported)
+ debug("user namespaces do not work on this system");
+
+ return supported;
+ }();
+ return res;
+}
+
+bool mountNamespacesSupported()
+{
+ static auto res = [&]() -> bool
+ {
+ bool useUserNamespace = userNamespacesSupported();
+
+ Pid pid = startProcess([&]()
+ {
+ auto res = unshare(CLONE_NEWNS | (useUserNamespace ? CLONE_NEWUSER : 0));
+ _exit(res ? 1 : 0);
+ });
+
+ bool supported = pid.wait() == 0;
+
+ if (!supported)
+ debug("mount namespaces do not work on this system");
+
+ return supported;
+ }();
+ return res;
+}
+
+bool pidNamespacesSupported()
+{
+ static auto res = [&]() -> bool
+ {
+ /* Check whether /proc is fully visible, i.e. there are no
+ filesystems mounted on top of files inside /proc. If this
+ is not the case, then we cannot mount a new /proc inside
+ the sandbox that matches the sandbox's PID namespace.
+ See https://lore.kernel.org/lkml/87tvsrjai0.fsf@xmission.com/T/. */
+ auto fp = fopen("/proc/mounts", "r");
+ if (!fp) return false;
+ Finally delFP = [&]() { fclose(fp); };
+
+ while (auto ent = getmntent(fp))
+ if (hasPrefix(std::string_view(ent->mnt_dir), "/proc/")) {
+ debug("PID namespaces do not work because /proc is not fully visible; disabling sandboxing");
+ return false;
+ }
+
+ return true;
+ }();
+ return res;
+}
+
+}
+
+#endif