aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/namespaces.cc
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2023-02-28 12:46:00 -0500
committerJohn Ericson <John.Ericson@Obsidian.Systems>2023-02-28 12:46:00 -0500
commit5abd643c6d10f2cfa6e26652a9688a0263310094 (patch)
tree2fdb8bf147cb93430ba3ba79a473568e2584e497 /src/libutil/namespaces.cc
parente68e8e3cee53ce7debd7c54b0d122d94d1b102a2 (diff)
parentd381248ec0847cacd918480e83a99287f814456a (diff)
Merge branch 'path-info' into ca-drv-exotic
Diffstat (limited to 'src/libutil/namespaces.cc')
-rw-r--r--src/libutil/namespaces.cc97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/libutil/namespaces.cc b/src/libutil/namespaces.cc
new file mode 100644
index 000000000..f66accb10
--- /dev/null
+++ b/src/libutil/namespaces.cc
@@ -0,0 +1,97 @@
+#if __linux__
+
+#include "namespaces.hh"
+#include "util.hh"
+#include "finally.hh"
+
+#include <sys/mount.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;
+ }
+
+ try {
+ Pid pid = startProcess([&]()
+ {
+ _exit(0);
+ }, {
+ .cloneFlags = CLONE_NEWUSER
+ });
+
+ auto r = pid.wait();
+ assert(!r);
+ } catch (SysError & e) {
+ debug("user namespaces do not work on this system: %s", e.msg());
+ return false;
+ }
+
+ return true;
+ }();
+ return res;
+}
+
+bool mountAndPidNamespacesSupported()
+{
+ static auto res = [&]() -> bool
+ {
+ try {
+
+ Pid pid = startProcess([&]()
+ {
+ /* Make sure we don't remount the parent's /proc. */
+ if (mount(0, "/", 0, MS_PRIVATE | MS_REC, 0) == -1)
+ _exit(1);
+
+ /* Test whether we can remount /proc. The kernel disallows
+ this if /proc is not fully visible, i.e. if there are
+ filesystems mounted on top of files inside /proc. See
+ https://lore.kernel.org/lkml/87tvsrjai0.fsf@xmission.com/T/. */
+ if (mount("none", "/proc", "proc", 0, 0) == -1)
+ _exit(2);
+
+ _exit(0);
+ }, {
+ .cloneFlags = CLONE_NEWNS | CLONE_NEWPID | (userNamespacesSupported() ? CLONE_NEWUSER : 0)
+ });
+
+ if (pid.wait()) {
+ debug("PID namespaces do not work on this system: cannot remount /proc");
+ return false;
+ }
+
+ } catch (SysError & e) {
+ debug("mount namespaces do not work on this system: %s", e.msg());
+ return false;
+ }
+
+ return true;
+ }();
+ return res;
+}
+
+}
+
+#endif