diff options
-rw-r--r-- | doc/manual/command-ref/conf-file.xml | 36 | ||||
-rw-r--r-- | src/libstore/build.cc | 47 | ||||
-rw-r--r-- | src/libstore/globals.cc | 2 | ||||
-rw-r--r-- | src/libstore/globals.hh | 3 |
4 files changed, 57 insertions, 31 deletions
diff --git a/doc/manual/command-ref/conf-file.xml b/doc/manual/command-ref/conf-file.xml index 91aa910a2946..cdfdc1a6e461 100644 --- a/doc/manual/command-ref/conf-file.xml +++ b/doc/manual/command-ref/conf-file.xml @@ -227,24 +227,32 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para> <varlistentry><term><literal>build-use-chroot</literal></term> <listitem><para>If set to <literal>true</literal>, builds will be - performed in a <emphasis>chroot environment</emphasis>, i.e., the - build will be isolated from the normal file system hierarchy and - will only see its dependencies in the Nix store, the temporary - build directory, private versions of <filename>/proc</filename>, + performed in a <emphasis>chroot environment</emphasis>, i.e., + they’re isolated from the normal file system hierarchy and will + only see their dependencies in the Nix store, the temporary build + directory, private versions of <filename>/proc</filename>, <filename>/dev</filename>, <filename>/dev/shm</filename> and <filename>/dev/pts</filename>, and the paths configured with the <link linkend='conf-build-chroot-dirs'><literal>build-chroot-dirs</literal> option</link>. This is useful to prevent undeclared dependencies - on files in directories such as - <filename>/usr/bin</filename>.</para> - - <para>The use of a chroot requires that Nix is run as root (so you - should use the <link linkend='conf-build-users-group'>“build - users” feature</link> to perform the actual builds under different - users than root). Currently, chroot builds only work on Linux - because Nix uses “bind mounts” to make the Nix store and other - directories available inside the chroot. Kernel version 3.13 or later - is needed.</para> + on files in directories such as <filename>/usr/bin</filename>. In + addition, on Linux, builds run in rivate PID, mount, network, IPC + and UTS namespaces to isolate them from other processes in the + system (except that fixed-output derivations do not run in private + network namespace to ensure they can access the network).</para> + + <para>Currently, chroots only work on Linux and Mac OS X. The use + of a chroot requires that Nix is run as root (so you should use + the <link linkend='conf-build-users-group'>“build users” + feature</link> to perform the actual builds under different users + than root).</para> + + <para>If this option is set to <literal>relaxed</literal>, then + fixed-output derivations and derivations that have the + <varname>__noChroot</varname> attribute set to + <literal>true</literal> do not run in chroots.</para> + + <para>The default is <literal>false</literal>.</para> </listitem> diff --git a/src/libstore/build.cc b/src/libstore/build.cc index e64bd3fef587..ac5ca7bc3a36 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -1768,12 +1768,20 @@ void DerivationGoal::startBuilder() functions like fetchurl (which needs a proper /etc/resolv.conf) work properly. Purity checking for fixed-output derivations is somewhat pointless anyway. */ - useChroot = settings.useChroot; - - if (fixedOutput) useChroot = false; - - /* Hack to allow derivations to disable chroot builds. */ - if (get(drv.env, "__noChroot") == "1") useChroot = false; + { + string x = settings.get("build-use-chroot", string("false")); + if (x != "true" && x != "false" && x != "relaxed") + throw Error("option ‘build-use-chroot’ must be set to one of ‘true’, ‘false’ or ‘relaxed’"); + if (x == "true") { + if (get(drv.env, "__noChroot") == "1") + throw Error(format("derivation ‘%1%’ has ‘__noChroot’ set, but that's not allowed when ‘build-use-chroot’ is ‘true’") % drvPath); + useChroot = true; + } + else if (x == "false") + useChroot = false; + else if (x == "relaxed") + useChroot = !fixedOutput && get(drv.env, "__noChroot") != "1"; + } if (useChroot) { /* Allow a user-configurable set of directories from the @@ -1856,7 +1864,8 @@ void DerivationGoal::startBuilder() % (buildUser.enabled() ? buildUser.getGID() : getgid())).str()); /* Create /etc/hosts with localhost entry. */ - writeFile(chrootRootDir + "/etc/hosts", "127.0.0.1 localhost\n"); + if (!fixedOutput) + writeFile(chrootRootDir + "/etc/hosts", "127.0.0.1 localhost\n"); /* Make the closure of the inputs available in the chroot, rather than the whole Nix store. This prevents any access @@ -1964,7 +1973,9 @@ void DerivationGoal::startBuilder() - The private network namespace ensures that the builder cannot talk to the outside world (or vice versa). It - only has a private loopback interface. + only has a private loopback interface. (Fixed-output + derivations are not run in a private network namespace + to allow functions like fetchurl to work.) - The IPC namespace prevents the builder from communicating with outside processes using SysV IPC mechanisms (shared @@ -1983,8 +1994,9 @@ void DerivationGoal::startBuilder() */ Pid helper = startProcess([&]() { char stack[32 * 1024]; - pid_t child = clone(childEntry, stack + sizeof(stack) - 8, - CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWNET | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD, this); + int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD; + if (!fixedOutput) flags |= CLONE_NEWNET; + pid_t child = clone(childEntry, stack + sizeof(stack) - 8, flags, this); if (child == -1) { if (errno == EINVAL) throw SysError("cloning builder process (Linux chroot builds require 3.13 or later)"); @@ -2081,10 +2093,10 @@ void DerivationGoal::runChild() /* Set up a nearly empty /dev, unless the user asked to bind-mount the host /dev. */ + Strings ss; if (dirsInChroot.find("/dev") == dirsInChroot.end()) { createDirs(chrootRootDir + "/dev/shm"); createDirs(chrootRootDir + "/dev/pts"); - Strings ss; ss.push_back("/dev/full"); #ifdef __linux__ if (pathExists("/dev/kvm")) @@ -2095,13 +2107,24 @@ void DerivationGoal::runChild() ss.push_back("/dev/tty"); ss.push_back("/dev/urandom"); ss.push_back("/dev/zero"); - foreach (Strings::iterator, i, ss) dirsInChroot[*i] = *i; createSymlink("/proc/self/fd", chrootRootDir + "/dev/fd"); createSymlink("/proc/self/fd/0", chrootRootDir + "/dev/stdin"); createSymlink("/proc/self/fd/1", chrootRootDir + "/dev/stdout"); createSymlink("/proc/self/fd/2", chrootRootDir + "/dev/stderr"); } + /* Fixed-output derivations typically need to access the + network, so give them access to /etc/resolv.conf and so + on. */ + if (fixedOutput) { + ss.push_back("/etc/resolv.conf"); + ss.push_back("/etc/nsswitch.conf"); + ss.push_back("/etc/services"); + ss.push_back("/etc/hosts"); + } + + for (auto & i : ss) dirsInChroot[i] = i; + /* Bind-mount all the directories from the "host" filesystem that we want in the chroot environment. */ diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index c5abeee282a3..e382b3aac03a 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -47,7 +47,6 @@ Settings::Settings() syncBeforeRegistering = false; useSubstitutes = true; buildUsersGroup = getuid() == 0 ? "nixbld" : ""; - useChroot = false; useSshSubstituter = true; impersonateLinux26 = false; keepLog = true; @@ -158,7 +157,6 @@ void Settings::update() _get(syncBeforeRegistering, "sync-before-registering"); _get(useSubstitutes, "build-use-substitutes"); _get(buildUsersGroup, "build-users-group"); - _get(useChroot, "build-use-chroot"); _get(impersonateLinux26, "build-impersonate-linux-26"); _get(keepLog, "build-keep-log"); _get(compressLog, "build-compress-log"); diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index c17e10d7c32d..0230a540e655 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -145,9 +145,6 @@ struct Settings { /* The Unix group that contains the build users. */ string buildUsersGroup; - /* Whether to build in chroot. */ - bool useChroot; - /* Set of ssh connection strings for the ssh substituter */ Strings sshSubstituterHosts; |