Use chroots for all derivations
If ‘build-use-chroot’ is set to ‘true’, fixed-output derivations are now also chrooted. However, unlike normal derivations, they don't get a private network namespace, so they can still access the network. Also, the use of the ‘__noChroot’ derivation attribute is no longer allowed. Setting ‘build-use-chroot’ to ‘relaxed’ gives the old behaviour.
This commit is contained in:
		
							parent
							
								
									15d2d3c34e
								
							
						
					
					
						commit
						99897f6979
					
				
					 4 changed files with 56 additions and 30 deletions
				
			
		| 
						 | 
					@ -227,24 +227,32 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
 | 
				
			||||||
  <varlistentry><term><literal>build-use-chroot</literal></term>
 | 
					  <varlistentry><term><literal>build-use-chroot</literal></term>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <listitem><para>If set to <literal>true</literal>, builds will be
 | 
					    <listitem><para>If set to <literal>true</literal>, builds will be
 | 
				
			||||||
    performed in a <emphasis>chroot environment</emphasis>, i.e., the
 | 
					    performed in a <emphasis>chroot environment</emphasis>, i.e.,
 | 
				
			||||||
    build will be isolated from the normal file system hierarchy and
 | 
					    they’re isolated from the normal file system hierarchy and will
 | 
				
			||||||
    will only see its dependencies in the Nix store, the temporary
 | 
					    only see their dependencies in the Nix store, the temporary build
 | 
				
			||||||
    build directory, private versions of <filename>/proc</filename>,
 | 
					    directory, private versions of <filename>/proc</filename>,
 | 
				
			||||||
    <filename>/dev</filename>, <filename>/dev/shm</filename> and
 | 
					    <filename>/dev</filename>, <filename>/dev/shm</filename> and
 | 
				
			||||||
    <filename>/dev/pts</filename>, and the paths configured with the
 | 
					    <filename>/dev/pts</filename>, and the paths configured with the
 | 
				
			||||||
    <link linkend='conf-build-chroot-dirs'><literal>build-chroot-dirs</literal>
 | 
					    <link linkend='conf-build-chroot-dirs'><literal>build-chroot-dirs</literal>
 | 
				
			||||||
    option</link>. This is useful to prevent undeclared dependencies
 | 
					    option</link>. This is useful to prevent undeclared dependencies
 | 
				
			||||||
    on files in directories such as
 | 
					    on files in directories such as <filename>/usr/bin</filename>. In
 | 
				
			||||||
    <filename>/usr/bin</filename>.</para>
 | 
					    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>The use of a chroot requires that Nix is run as root (so you
 | 
					    <para>Currently, chroots only work on Linux and Mac OS X. The use
 | 
				
			||||||
    should use the <link linkend='conf-build-users-group'>“build
 | 
					    of a chroot requires that Nix is run as root (so you should use
 | 
				
			||||||
    users” feature</link> to perform the actual builds under different
 | 
					    the <link linkend='conf-build-users-group'>“build users”
 | 
				
			||||||
    users than root).  Currently, chroot builds only work on Linux
 | 
					    feature</link> to perform the actual builds under different users
 | 
				
			||||||
    because Nix uses “bind mounts” to make the Nix store and other
 | 
					    than root).</para>
 | 
				
			||||||
    directories available inside the chroot. Kernel version 3.13 or later
 | 
					
 | 
				
			||||||
    is needed.</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>
 | 
					    </listitem>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1768,12 +1768,20 @@ void DerivationGoal::startBuilder()
 | 
				
			||||||
       functions like fetchurl (which needs a proper /etc/resolv.conf)
 | 
					       functions like fetchurl (which needs a proper /etc/resolv.conf)
 | 
				
			||||||
       work properly.  Purity checking for fixed-output derivations
 | 
					       work properly.  Purity checking for fixed-output derivations
 | 
				
			||||||
       is somewhat pointless anyway. */
 | 
					       is somewhat pointless anyway. */
 | 
				
			||||||
    useChroot = settings.useChroot;
 | 
					    {
 | 
				
			||||||
 | 
					        string x = settings.get("build-use-chroot", string("false"));
 | 
				
			||||||
    if (fixedOutput) useChroot = false;
 | 
					        if (x != "true" && x != "false" && x != "relaxed")
 | 
				
			||||||
 | 
					            throw Error("option ‘build-use-chroot’ must be set to one of ‘true’, ‘false’ or ‘relaxed’");
 | 
				
			||||||
    /* Hack to allow derivations to disable chroot builds. */
 | 
					        if (x == "true") {
 | 
				
			||||||
    if (get(drv.env, "__noChroot") == "1") useChroot = false;
 | 
					            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) {
 | 
					    if (useChroot) {
 | 
				
			||||||
        /* Allow a user-configurable set of directories from the
 | 
					        /* Allow a user-configurable set of directories from the
 | 
				
			||||||
| 
						 | 
					@ -1856,7 +1864,8 @@ void DerivationGoal::startBuilder()
 | 
				
			||||||
                % (buildUser.enabled() ? buildUser.getGID() : getgid())).str());
 | 
					                % (buildUser.enabled() ? buildUser.getGID() : getgid())).str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Create /etc/hosts with localhost entry. */
 | 
					        /* 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,
 | 
					        /* Make the closure of the inputs available in the chroot,
 | 
				
			||||||
           rather than the whole Nix store.  This prevents any access
 | 
					           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
 | 
					           - The private network namespace ensures that the builder
 | 
				
			||||||
             cannot talk to the outside world (or vice versa).  It
 | 
					             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
 | 
					           - The IPC namespace prevents the builder from communicating
 | 
				
			||||||
             with outside processes using SysV IPC mechanisms (shared
 | 
					             with outside processes using SysV IPC mechanisms (shared
 | 
				
			||||||
| 
						 | 
					@ -1983,8 +1994,9 @@ void DerivationGoal::startBuilder()
 | 
				
			||||||
        */
 | 
					        */
 | 
				
			||||||
        Pid helper = startProcess([&]() {
 | 
					        Pid helper = startProcess([&]() {
 | 
				
			||||||
            char stack[32 * 1024];
 | 
					            char stack[32 * 1024];
 | 
				
			||||||
            pid_t child = clone(childEntry, stack + sizeof(stack) - 8,
 | 
					            int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD;
 | 
				
			||||||
                CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWNET | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD, this);
 | 
					            if (!fixedOutput) flags |= CLONE_NEWNET;
 | 
				
			||||||
 | 
					            pid_t child = clone(childEntry, stack + sizeof(stack) - 8, flags, this);
 | 
				
			||||||
            if (child == -1) {
 | 
					            if (child == -1) {
 | 
				
			||||||
                if (errno == EINVAL)
 | 
					                if (errno == EINVAL)
 | 
				
			||||||
                    throw SysError("cloning builder process (Linux chroot builds require 3.13 or later)");
 | 
					                    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
 | 
					            /* Set up a nearly empty /dev, unless the user asked to
 | 
				
			||||||
               bind-mount the host /dev. */
 | 
					               bind-mount the host /dev. */
 | 
				
			||||||
 | 
					            Strings ss;
 | 
				
			||||||
            if (dirsInChroot.find("/dev") == dirsInChroot.end()) {
 | 
					            if (dirsInChroot.find("/dev") == dirsInChroot.end()) {
 | 
				
			||||||
                createDirs(chrootRootDir + "/dev/shm");
 | 
					                createDirs(chrootRootDir + "/dev/shm");
 | 
				
			||||||
                createDirs(chrootRootDir + "/dev/pts");
 | 
					                createDirs(chrootRootDir + "/dev/pts");
 | 
				
			||||||
                Strings ss;
 | 
					 | 
				
			||||||
                ss.push_back("/dev/full");
 | 
					                ss.push_back("/dev/full");
 | 
				
			||||||
#ifdef __linux__
 | 
					#ifdef __linux__
 | 
				
			||||||
                if (pathExists("/dev/kvm"))
 | 
					                if (pathExists("/dev/kvm"))
 | 
				
			||||||
| 
						 | 
					@ -2095,13 +2107,24 @@ void DerivationGoal::runChild()
 | 
				
			||||||
                ss.push_back("/dev/tty");
 | 
					                ss.push_back("/dev/tty");
 | 
				
			||||||
                ss.push_back("/dev/urandom");
 | 
					                ss.push_back("/dev/urandom");
 | 
				
			||||||
                ss.push_back("/dev/zero");
 | 
					                ss.push_back("/dev/zero");
 | 
				
			||||||
                foreach (Strings::iterator, i, ss) dirsInChroot[*i] = *i;
 | 
					 | 
				
			||||||
                createSymlink("/proc/self/fd", chrootRootDir + "/dev/fd");
 | 
					                createSymlink("/proc/self/fd", chrootRootDir + "/dev/fd");
 | 
				
			||||||
                createSymlink("/proc/self/fd/0", chrootRootDir + "/dev/stdin");
 | 
					                createSymlink("/proc/self/fd/0", chrootRootDir + "/dev/stdin");
 | 
				
			||||||
                createSymlink("/proc/self/fd/1", chrootRootDir + "/dev/stdout");
 | 
					                createSymlink("/proc/self/fd/1", chrootRootDir + "/dev/stdout");
 | 
				
			||||||
                createSymlink("/proc/self/fd/2", chrootRootDir + "/dev/stderr");
 | 
					                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"
 | 
					            /* Bind-mount all the directories from the "host"
 | 
				
			||||||
               filesystem that we want in the chroot
 | 
					               filesystem that we want in the chroot
 | 
				
			||||||
               environment. */
 | 
					               environment. */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,7 +47,6 @@ Settings::Settings()
 | 
				
			||||||
    syncBeforeRegistering = false;
 | 
					    syncBeforeRegistering = false;
 | 
				
			||||||
    useSubstitutes = true;
 | 
					    useSubstitutes = true;
 | 
				
			||||||
    buildUsersGroup = getuid() == 0 ? "nixbld" : "";
 | 
					    buildUsersGroup = getuid() == 0 ? "nixbld" : "";
 | 
				
			||||||
    useChroot = false;
 | 
					 | 
				
			||||||
    useSshSubstituter = true;
 | 
					    useSshSubstituter = true;
 | 
				
			||||||
    impersonateLinux26 = false;
 | 
					    impersonateLinux26 = false;
 | 
				
			||||||
    keepLog = true;
 | 
					    keepLog = true;
 | 
				
			||||||
| 
						 | 
					@ -158,7 +157,6 @@ void Settings::update()
 | 
				
			||||||
    _get(syncBeforeRegistering, "sync-before-registering");
 | 
					    _get(syncBeforeRegistering, "sync-before-registering");
 | 
				
			||||||
    _get(useSubstitutes, "build-use-substitutes");
 | 
					    _get(useSubstitutes, "build-use-substitutes");
 | 
				
			||||||
    _get(buildUsersGroup, "build-users-group");
 | 
					    _get(buildUsersGroup, "build-users-group");
 | 
				
			||||||
    _get(useChroot, "build-use-chroot");
 | 
					 | 
				
			||||||
    _get(impersonateLinux26, "build-impersonate-linux-26");
 | 
					    _get(impersonateLinux26, "build-impersonate-linux-26");
 | 
				
			||||||
    _get(keepLog, "build-keep-log");
 | 
					    _get(keepLog, "build-keep-log");
 | 
				
			||||||
    _get(compressLog, "build-compress-log");
 | 
					    _get(compressLog, "build-compress-log");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -145,9 +145,6 @@ struct Settings {
 | 
				
			||||||
    /* The Unix group that contains the build users. */
 | 
					    /* The Unix group that contains the build users. */
 | 
				
			||||||
    string buildUsersGroup;
 | 
					    string buildUsersGroup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Whether to build in chroot. */
 | 
					 | 
				
			||||||
    bool useChroot;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Set of ssh connection strings for the ssh substituter */
 | 
					    /* Set of ssh connection strings for the ssh substituter */
 | 
				
			||||||
    Strings sshSubstituterHosts;
 | 
					    Strings sshSubstituterHosts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue