about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Bauer <mjbauer95@gmail.com>2019-07-25T18·29-0400
committerMatthew Bauer <mjbauer95@gmail.com>2019-07-25T18·42-0400
commit11d853462925d0b57fe956962e07edf5751fd4c3 (patch)
treec42900966dd0f3dae262fbe7092fd678fdb0c05e
parentd171090530f4a2a79efec2c385bee1a10844c706 (diff)
Use sandbox fallback when cloning fails in builder
When sandbox-fallback = true (the default), the Nix builder will fall
back to disabled sandbox mode when the kernel doesn’t allow users to
set it up. This prevents hard errors from occuring in tricky places,
especially the initial installer. To restore the previous behavior,
users can set:

  sandbox-fallback = false

in their /etc/nix/nix.conf configuration.
-rw-r--r--src/libstore/build.cc12
-rw-r--r--src/libstore/globals.hh3
2 files changed, 14 insertions, 1 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index c10005839bf7..dd08ce7d771f 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -2316,13 +2316,22 @@ void DerivationGoal::startBuilder()
                 flags &= ~CLONE_NEWUSER;
                 child = clone(childEntry, stack + stackSize, flags, this);
             }
+            /* Otherwise exit with EPERM so we can handle this in the
+               parent. This is only done when sandbox-fallback is set
+               to true (the default). */
+            if (child == -1 && (errno == EPERM || errno == EINVAL) && settings.sandboxFallback)
+                _exit(EPERM);
             if (child == -1) throw SysError("cloning builder process");
 
             writeFull(builderOut.writeSide.get(), std::to_string(child) + "\n");
             _exit(0);
         }, options);
 
-        if (helper.wait() != 0)
+        int res = helper.wait();
+        if (res == EPERM && settings.sandboxFallback) {
+            useChroot = false;
+            goto fallback;
+        } else if (res != 0)
             throw Error("unable to start build process");
 
         userNamespaceSync.readSide = -1;
@@ -2353,6 +2362,7 @@ void DerivationGoal::startBuilder()
     } else
 #endif
     {
+    fallback:
         options.allowVfork = !buildUser && !drv->isBuiltin();
         pid = startProcess([&]() {
             runChild();
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 0af8215d1fd8..cc9534b2794d 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -209,6 +209,9 @@ public:
         "The paths to make available inside the build sandbox.",
         {"build-chroot-dirs", "build-sandbox-paths"}};
 
+    Setting<bool> sandboxFallback{this, true, "sandbox-fallback",
+        "Whether to disable sandboxing when the kernel doesn't allow it."};
+
     Setting<PathSet> extraSandboxPaths{this, {}, "extra-sandbox-paths",
         "Additional paths to make available inside the build sandbox.",
         {"build-extra-chroot-dirs", "build-extra-sandbox-paths"}};