mirror of
https://github.com/NixOS/nix.git
synced 2024-11-27 01:02:34 +00:00
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
@ -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…
Reference in New Issue
Block a user