about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Bauer <mjbauer95@gmail.com>2019-07-25T13·37-0400
committerMatthew Bauer <mjbauer95@gmail.com>2019-07-25T18·42-0400
commitd171090530f4a2a79efec2c385bee1a10844c706 (patch)
tree709ddf2bd276cb5cea94b7a4088547b37ec67c76
parentb640f69a4d33eb3833cf0ac3000d189dacbd0f5a (diff)
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.
-rw-r--r--src/libstore/build.cc14
-rw-r--r--src/nix/run.cc5
2 files changed, 16 insertions, 3 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index cf6428e12467..c10005839bf7 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -2302,10 +2302,20 @@ void DerivationGoal::startBuilder()
                 flags |= CLONE_NEWNET;
 
             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
                    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");
 
             writeFull(builderOut.writeSide.get(), std::to_string(child) + "\n");
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 35b763345872..90b76d6663e9 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -199,7 +199,10 @@ void chrootHelper(int argc, char * * argv)
     uid_t gid = getgid();
 
     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
        point doesn't already exists, we have to create a chroot