Skip to content

Commit

Permalink
Use chroots for all derivations
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
edolstra committed Feb 23, 2015
1 parent 15d2d3c commit 99897f6
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 31 deletions.
36 changes: 22 additions & 14 deletions doc/manual/command-ref/conf-file.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down
47 changes: 35 additions & 12 deletions src/libstore/build.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)");
Expand Down Expand Up @@ -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"))
Expand All @@ -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. */
Expand Down
2 changes: 0 additions & 2 deletions src/libstore/globals.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ Settings::Settings()
syncBeforeRegistering = false;
useSubstitutes = true;
buildUsersGroup = getuid() == 0 ? "nixbld" : "";
useChroot = false;
useSshSubstituter = true;
impersonateLinux26 = false;
keepLog = true;
Expand Down Expand Up @@ -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");
Expand Down
3 changes: 0 additions & 3 deletions src/libstore/globals.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit 99897f6

Please sign in to comment.