aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2020-10-07 22:02:36 +0200
committerEelco Dolstra <edolstra@gmail.com>2020-10-07 22:02:36 +0200
commit6aa64627c8e431c3b187f7bb44c943d06e39b929 (patch)
tree5d3d5653183942f8bbc54526812b6d17855cd9c4
parentf66bbd8c7bb1472facf8917e58e3cd4f6ddfa1b5 (diff)
Support user namespaces being disabled
If max_user_namespaces is set to 0, then don't run the build in a user namespace. Fixes #4092.
-rw-r--r--src/libstore/build.cc54
1 files changed, 40 insertions, 14 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index e1774237b..a645c429d 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -831,6 +831,10 @@ private:
paths to the sandbox as a result of recursive Nix calls. */
AutoCloseFD sandboxMountNamespace;
+ /* On Linux, whether we're doing the build in its own user
+ namespace. */
+ bool usingUserNamespace = true;
+
/* The build hook. */
std::unique_ptr<HookInstance> hook;
@@ -920,8 +924,8 @@ private:
result. */
std::map<Path, ValidPathInfo> prevInfos;
- const uid_t sandboxUid = 1000;
- const gid_t sandboxGid = 100;
+ uid_t sandboxUid = 1000;
+ gid_t sandboxGid = 100;
const static Path homeDir;
@@ -2629,6 +2633,24 @@ void DerivationGoal::startBuilder()
options.allowVfork = false;
+ Path maxUserNamespaces = "/proc/sys/user/max_user_namespaces";
+ static bool userNamespacesEnabled =
+ pathExists(maxUserNamespaces)
+ && trim(readFile(maxUserNamespaces)) != "0";
+
+ usingUserNamespace = userNamespacesEnabled;
+
+ if (usingUserNamespace) {
+ sandboxUid = 1000;
+ sandboxGid = 100;
+ } else {
+ debug("note: not using a user namespace");
+ if (!buildUser)
+ throw Error("cannot perform a sandboxed build because user namespaces are not enabled; check /proc/sys/user/max_user_namespaces");
+ sandboxUid = buildUser->getUID();
+ sandboxGid = buildUser->getGID();
+ }
+
Pid helper = startProcess([&]() {
/* Drop additional groups here because we can't do it
@@ -2647,9 +2669,11 @@ void DerivationGoal::startBuilder()
PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
if (stack == MAP_FAILED) throw SysError("allocating stack");
- int flags = CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD;
+ int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD;
if (privateNetwork)
flags |= CLONE_NEWNET;
+ if (usingUserNamespace)
+ flags |= CLONE_NEWUSER;
pid_t child = clone(childEntry, stack + stackSize, flags, this);
if (child == -1 && errno == EINVAL) {
@@ -2697,19 +2721,21 @@ void DerivationGoal::startBuilder()
if (!string2Int<pid_t>(readLine(builderOut.readSide.get()), tmp)) abort();
pid = tmp;
- /* Set the UID/GID mapping of the builder's user namespace
- such that the sandbox user maps to the build user, or to
- the calling user (if build users are disabled). */
- uid_t hostUid = buildUser ? buildUser->getUID() : getuid();
- uid_t hostGid = buildUser ? buildUser->getGID() : getgid();
+ if (usingUserNamespace) {
+ /* Set the UID/GID mapping of the builder's user namespace
+ such that the sandbox user maps to the build user, or to
+ the calling user (if build users are disabled). */
+ uid_t hostUid = buildUser ? buildUser->getUID() : getuid();
+ uid_t hostGid = buildUser ? buildUser->getGID() : getgid();
- writeFile("/proc/" + std::to_string(pid) + "/uid_map",
- (format("%d %d 1") % sandboxUid % hostUid).str());
+ writeFile("/proc/" + std::to_string(pid) + "/uid_map",
+ (format("%d %d 1") % sandboxUid % hostUid).str());
- writeFile("/proc/" + std::to_string(pid) + "/setgroups", "deny");
+ writeFile("/proc/" + std::to_string(pid) + "/setgroups", "deny");
- writeFile("/proc/" + std::to_string(pid) + "/gid_map",
- (format("%d %d 1") % sandboxGid % hostGid).str());
+ writeFile("/proc/" + std::to_string(pid) + "/gid_map",
+ (format("%d %d 1") % sandboxGid % hostGid).str());
+ }
/* Save the mount namespace of the child. We have to do this
*before* the child does a chroot. */
@@ -2745,7 +2771,7 @@ void DerivationGoal::startBuilder()
ex.addTrace({}, "while setting up the build environment");
throw ex;
}
- debug(msg);
+ debug("sandbox setup: " + msg);
}
}