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.
This commit is contained in:
Matthew Bauer 2019-07-25 14:29:58 -04:00
parent d171090530
commit 11d8534629
2 changed files with 14 additions and 1 deletions

View file

@ -2316,13 +2316,22 @@ void DerivationGoal::startBuilder()
flags &= ~CLONE_NEWUSER; flags &= ~CLONE_NEWUSER;
child = clone(childEntry, stack + stackSize, flags, this); 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"); if (child == -1) throw SysError("cloning builder process");
writeFull(builderOut.writeSide.get(), std::to_string(child) + "\n"); writeFull(builderOut.writeSide.get(), std::to_string(child) + "\n");
_exit(0); _exit(0);
}, options); }, 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"); throw Error("unable to start build process");
userNamespaceSync.readSide = -1; userNamespaceSync.readSide = -1;
@ -2353,6 +2362,7 @@ void DerivationGoal::startBuilder()
} else } else
#endif #endif
{ {
fallback:
options.allowVfork = !buildUser && !drv->isBuiltin(); options.allowVfork = !buildUser && !drv->isBuiltin();
pid = startProcess([&]() { pid = startProcess([&]() {
runChild(); runChild();

View file

@ -209,6 +209,9 @@ public:
"The paths to make available inside the build sandbox.", "The paths to make available inside the build sandbox.",
{"build-chroot-dirs", "build-sandbox-paths"}}; {"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", Setting<PathSet> extraSandboxPaths{this, {}, "extra-sandbox-paths",
"Additional paths to make available inside the build sandbox.", "Additional paths to make available inside the build sandbox.",
{"build-extra-chroot-dirs", "build-extra-sandbox-paths"}}; {"build-extra-chroot-dirs", "build-extra-sandbox-paths"}};