Merge commit '6aa64627c8e431c3b187f7bb44c943d06e39b929' into auto-uid-allocation

This commit is contained in:
John Ericson 2020-10-17 19:12:59 +00:00
commit 81c5f754a7

View file

@ -720,6 +720,10 @@ private:
paths to the sandbox as a result of recursive Nix calls. */ paths to the sandbox as a result of recursive Nix calls. */
AutoCloseFD sandboxMountNamespace; AutoCloseFD sandboxMountNamespace;
/* On Linux, whether we're doing the build in its own user
namespace. */
bool usingUserNamespace = true;
/* The build hook. */ /* The build hook. */
std::unique_ptr<HookInstance> hook; std::unique_ptr<HookInstance> hook;
@ -2319,8 +2323,8 @@ void DerivationGoal::startBuilder()
if (useUidRange && (!buildUser || buildUser->getUIDCount() < 65536)) if (useUidRange && (!buildUser || buildUser->getUIDCount() < 65536))
throw Error("feature 'uid-range' requires '%s' to be enabled", settings.autoAllocateUids.name); throw Error("feature 'uid-range' requires '%s' to be enabled", settings.autoAllocateUids.name);
sandboxUid = useUidRange ? 0 : 1000; sandboxUid = useUidRange && usingUserNamespace ? 0 : 1000;
sandboxGid = useUidRange ? 0 : 100; sandboxGid = useUidRange && usingUserNamespace ? 0 : 100;
writeFile(chrootRootDir + "/etc/passwd", fmt( writeFile(chrootRootDir + "/etc/passwd", fmt(
"root:x:0:0:Nix build user:%3%:/noshell\n" "root:x:0:0:Nix build user:%3%:/noshell\n"
@ -2551,6 +2555,24 @@ void DerivationGoal::startBuilder()
options.allowVfork = false; 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([&]() { Pid helper = startProcess([&]() {
/* Drop additional groups here because we can't do it /* Drop additional groups here because we can't do it
@ -2569,9 +2591,11 @@ void DerivationGoal::startBuilder()
PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
if (stack == MAP_FAILED) throw SysError("allocating stack"); 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) if (privateNetwork)
flags |= CLONE_NEWNET; flags |= CLONE_NEWNET;
if (usingUserNamespace)
flags |= CLONE_NEWUSER;
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) {
@ -2619,21 +2643,23 @@ void DerivationGoal::startBuilder()
if (!string2Int<pid_t>(readLine(builderOut.readSide.get()), tmp)) abort(); if (!string2Int<pid_t>(readLine(builderOut.readSide.get()), tmp)) abort();
pid = tmp; pid = tmp;
/* Set the UID/GID mapping of the builder's user namespace if (usingUserNamespace) {
such that the sandbox user maps to the build user, or to /* Set the UID/GID mapping of the builder's user namespace
the calling user (if build users are disabled). */ such that the sandbox user maps to the build user, or to
uid_t hostUid = buildUser ? buildUser->getUID() : getuid(); the calling user (if build users are disabled). */
uid_t hostGid = buildUser ? buildUser->getGID() : getgid(); uid_t hostUid = buildUser ? buildUser->getUID() : getuid();
uint32_t nrIds = buildUser && useUidRange ? buildUser->getUIDCount() : 1; uid_t hostGid = buildUser ? buildUser->getGID() : getgid();
uint32_t nrIds = buildUser && useUidRange ? buildUser->getUIDCount() : 1;
writeFile("/proc/" + std::to_string(pid) + "/uid_map", writeFile("/proc/" + std::to_string(pid) + "/uid_map",
fmt("%d %d %d", sandboxUid, hostUid, nrIds)); fmt("%d %d %d", sandboxUid, hostUid, nrIds));
if (!useUidRange) if (!useUidRange)
writeFile("/proc/" + std::to_string(pid) + "/setgroups", "deny"); writeFile("/proc/" + std::to_string(pid) + "/setgroups", "deny");
writeFile("/proc/" + std::to_string(pid) + "/gid_map", writeFile("/proc/" + std::to_string(pid) + "/gid_map",
fmt("%d %d %d", sandboxGid, hostGid, nrIds)); fmt("%d %d %d", sandboxGid, hostGid, nrIds));
}
/* Save the mount namespace of the child. We have to do this /* Save the mount namespace of the child. We have to do this
*before* the child does a chroot. */ *before* the child does a chroot. */
@ -2675,7 +2701,7 @@ void DerivationGoal::startBuilder()
ex.addTrace({}, "while setting up the build environment"); ex.addTrace({}, "while setting up the build environment");
throw ex; throw ex;
} }
debug(msg); debug("sandbox setup: " + msg);
} }
} }