Disable CLONE_NEWUSER when it’s unavailable

Some kernels disable "unpriveleged user namespaces". This is
unfortunate, but we can still use mount namespaces. Anyway, since each
builder has its own nixbld user, we already have most of the benefits
of user namespaces.
This commit is contained in:
Matthew Bauer 2019-07-25 09:37:57 -04:00
parent b640f69a4d
commit d171090530
2 changed files with 16 additions and 3 deletions

View file

@ -2302,10 +2302,20 @@ void DerivationGoal::startBuilder()
flags |= CLONE_NEWNET; flags |= CLONE_NEWNET;
pid_t child = clone(childEntry, stack + stackSize, flags, this); pid_t child = clone(childEntry, stack + stackSize, flags, this);
if (child == -1 && errno == EINVAL) if (child == -1 && errno == EINVAL) {
/* Fallback for Linux < 2.13 where CLONE_NEWPID and /* Fallback for Linux < 2.13 where CLONE_NEWPID and
CLONE_PARENT are not allowed together. */ CLONE_PARENT are not allowed together. */
child = clone(childEntry, stack + stackSize, flags & ~CLONE_NEWPID, this); flags &= ~CLONE_NEWPID;
child = clone(childEntry, stack + stackSize, flags, this);
}
if (child == -1 && (errno == EPERM || errno == EINVAL)) {
/* Some distros patch Linux to not allow unpriveleged
* user namespaces. If we get EPERM or EINVAL, try
* without CLONE_NEWUSER and see if that works.
*/
flags &= ~CLONE_NEWUSER;
child = clone(childEntry, stack + stackSize, flags, this);
}
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");

View file

@ -199,7 +199,10 @@ void chrootHelper(int argc, char * * argv)
uid_t gid = getgid(); uid_t gid = getgid();
if (unshare(CLONE_NEWUSER | CLONE_NEWNS) == -1) if (unshare(CLONE_NEWUSER | CLONE_NEWNS) == -1)
throw SysError("setting up a private mount namespace"); /* Try with just CLONE_NEWNS in case user namespaces are
specifically disabled. */
if (unshare(CLONE_NEWNS) == -1)
throw SysError("setting up a private mount namespace");
/* Bind-mount realStoreDir on /nix/store. If the latter mount /* Bind-mount realStoreDir on /nix/store. If the latter mount
point doesn't already exists, we have to create a chroot point doesn't already exists, we have to create a chroot