aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libstore/build/local-derivation-goal.cc96
-rw-r--r--src/libstore/build/local-derivation-goal.hh17
-rw-r--r--src/libstore/platform/darwin.hh6
-rw-r--r--src/libstore/platform/linux.cc88
-rw-r--r--src/libstore/platform/linux.hh16
5 files changed, 130 insertions, 93 deletions
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index 1dd2ad8aa..bc8879428 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -659,101 +659,11 @@ void LocalDerivationGoal::startBuilder()
pathsInChroot[i] = {i, true};
}
-#if __linux__
- /* Create a temporary directory in which we set up the chroot
- environment using bind-mounts. We put it in the Nix store
- to ensure that we can create hard-links to non-directory
- inputs in the fake Nix store in the chroot (see below). */
- chrootRootDir = worker.store.Store::toRealPath(drvPath) + ".chroot";
- deletePath(chrootRootDir);
-
- /* Clean up the chroot directory automatically. */
- autoDelChroot = std::make_shared<AutoDelete>(chrootRootDir);
-
- printMsg(lvlChatty, "setting up chroot environment in '%1%'", chrootRootDir);
-
- // FIXME: make this 0700
- if (mkdir(chrootRootDir.c_str(), buildUser && buildUser->getUIDCount() != 1 ? 0755 : 0750) == -1)
- throw SysError("cannot create '%1%'", chrootRootDir);
-
- if (buildUser && chown(chrootRootDir.c_str(), buildUser->getUIDCount() != 1 ? buildUser->getUID() : 0, buildUser->getGID()) == -1)
- throw SysError("cannot change ownership of '%1%'", chrootRootDir);
-
- /* Create a writable /tmp in the chroot. Many builders need
- this. (Of course they should really respect $TMPDIR
- instead.) */
- Path chrootTmpDir = chrootRootDir + "/tmp";
- createDirs(chrootTmpDir);
- chmodPath(chrootTmpDir, 01777);
-
- /* Create a /etc/passwd with entries for the build user and the
- nobody account. The latter is kind of a hack to support
- Samba-in-QEMU. */
- createDirs(chrootRootDir + "/etc");
- if (parsedDrv->useUidRange())
- chownToBuilder(chrootRootDir + "/etc");
-
- if (parsedDrv->useUidRange() && (!buildUser || buildUser->getUIDCount() < 65536))
- throw Error("feature 'uid-range' requires the setting '%s' to be enabled", settings.autoAllocateUids.name);
-
- /* Create /etc/hosts with localhost entry. */
- if (derivationType->isSandboxed())
- writeFile(chrootRootDir + "/etc/hosts", "127.0.0.1 localhost\n::1 localhost\n");
-
- /* Make the closure of the inputs available in the chroot,
- rather than the whole Nix store. This prevents any access
- to undeclared dependencies. Directories are bind-mounted,
- while other inputs are hard-linked (since only directories
- can be bind-mounted). !!! As an extra security
- precaution, make the fake Nix store only writable by the
- build user. */
- Path chrootStoreDir = chrootRootDir + worker.store.storeDir;
- createDirs(chrootStoreDir);
- chmodPath(chrootStoreDir, 01775);
-
- if (buildUser && chown(chrootStoreDir.c_str(), 0, buildUser->getGID()) == -1)
- throw SysError("cannot change ownership of '%1%'", chrootStoreDir);
-
- for (auto & i : inputPaths) {
- auto p = worker.store.printStorePath(i);
- Path r = worker.store.toRealPath(p);
- pathsInChroot.insert_or_assign(p, r);
- }
-
- /* If we're repairing, checking or rebuilding part of a
- multiple-outputs derivation, it's possible that we're
- rebuilding a path that is in settings.sandbox-paths
- (typically the dependencies of /bin/sh). Throw them
- out. */
- for (auto & i : drv->outputsAndOptPaths(worker.store)) {
- /* If the name isn't known a priori (i.e. floating
- content-addressed derivation), the temporary location we use
- should be fresh. Freshness means it is impossible that the path
- is already in the sandbox, so we don't need to worry about
- removing it. */
- if (i.second.second)
- pathsInChroot.erase(worker.store.printStorePath(*i.second.second));
- }
+ if (parsedDrv->useUidRange() && !supportsUidRange())
+ throw Error("feature 'uid-range' is not supported on this platform");
- if (cgroup) {
- if (mkdir(cgroup->c_str(), 0755) != 0)
- throw SysError("creating cgroup '%s'", *cgroup);
- chownToBuilder(*cgroup);
- chownToBuilder(*cgroup + "/cgroup.procs");
- chownToBuilder(*cgroup + "/cgroup.threads");
- //chownToBuilder(*cgroup + "/cgroup.subtree_control");
- }
+ prepareSandbox();
-#else
- if (parsedDrv->useUidRange())
- throw Error("feature 'uid-range' is not supported on this platform");
- #if __APPLE__
- /* We don't really have any parent prep work to do (yet?)
- All work happens in the child, instead. */
- #else
- throw Error("sandboxing builds is not supported on this platform");
- #endif
-#endif
} else {
if (parsedDrv->useUidRange())
throw Error("feature 'uid-range' is only supported in sandboxed builds");
diff --git a/src/libstore/build/local-derivation-goal.hh b/src/libstore/build/local-derivation-goal.hh
index 91329ca35..857339b5d 100644
--- a/src/libstore/build/local-derivation-goal.hh
+++ b/src/libstore/build/local-derivation-goal.hh
@@ -325,11 +325,28 @@ protected:
using DerivationGoal::DerivationGoal;
/**
+ * Setup dependencies outside the sandbox.
+ * Called in the parent nix process.
+ */
+ virtual void prepareSandbox()
+ {
+ throw Error("sandboxing builds is not supported on this platform");
+ };
+
+ /**
* Execute the builder, replacing the current process.
* Generally this means an `execve` call.
*/
virtual void execBuilder(std::string builder, Strings args, Strings envStrs);
+ /**
+ * Whether derivation can be built on current platform with `uid-range` feature
+ */
+ virtual bool supportsUidRange()
+ {
+ return false;
+ }
+
};
}
diff --git a/src/libstore/platform/darwin.hh b/src/libstore/platform/darwin.hh
index 0ac7077fb..70e8a8587 100644
--- a/src/libstore/platform/darwin.hh
+++ b/src/libstore/platform/darwin.hh
@@ -43,6 +43,12 @@ public:
private:
/**
+ * Prepare the sandbox: This is empty on Darwin since sandbox setup happens in
+ * enterSandbox
+ */
+ void prepareSandbox() override{};
+
+ /**
* Set process flags to enter or leave rosetta, then execute the builder
*/
void execBuilder(std::string builder, Strings args, Strings envStrs) override;
diff --git a/src/libstore/platform/linux.cc b/src/libstore/platform/linux.cc
index 6b94c01cc..ac0440e5a 100644
--- a/src/libstore/platform/linux.cc
+++ b/src/libstore/platform/linux.cc
@@ -1,3 +1,4 @@
+#include "build/worker.hh"
#include "cgroup.hh"
#include "gc-store.hh"
#include "signals.hh"
@@ -116,6 +117,93 @@ void LinuxLocalStore::findPlatformRoots(UncheckedRoots & unchecked)
readFileRoots("/proc/sys/kernel/poweroff_cmd", unchecked);
}
+void LinuxLocalDerivationGoal::prepareSandbox()
+{
+ /* Create a temporary directory in which we set up the chroot
+ environment using bind-mounts. We put it in the Nix store
+ to ensure that we can create hard-links to non-directory
+ inputs in the fake Nix store in the chroot (see below). */
+ chrootRootDir = worker.store.Store::toRealPath(drvPath) + ".chroot";
+ deletePath(chrootRootDir);
+
+ /* Clean up the chroot directory automatically. */
+ autoDelChroot = std::make_shared<AutoDelete>(chrootRootDir);
+
+ printMsg(lvlChatty, "setting up chroot environment in '%1%'", chrootRootDir);
+
+ // FIXME: make this 0700
+ if (mkdir(chrootRootDir.c_str(), buildUser && buildUser->getUIDCount() != 1 ? 0755 : 0750) == -1)
+ throw SysError("cannot create '%1%'", chrootRootDir);
+
+ if (buildUser && chown(chrootRootDir.c_str(), buildUser->getUIDCount() != 1 ? buildUser->getUID() : 0, buildUser->getGID()) == -1)
+ throw SysError("cannot change ownership of '%1%'", chrootRootDir);
+
+ /* Create a writable /tmp in the chroot. Many builders need
+ this. (Of course they should really respect $TMPDIR
+ instead.) */
+ Path chrootTmpDir = chrootRootDir + "/tmp";
+ createDirs(chrootTmpDir);
+ chmodPath(chrootTmpDir, 01777);
+
+ /* Create a /etc/passwd with entries for the build user and the
+ nobody account. The latter is kind of a hack to support
+ Samba-in-QEMU. */
+ createDirs(chrootRootDir + "/etc");
+ if (parsedDrv->useUidRange())
+ chownToBuilder(chrootRootDir + "/etc");
+
+ if (parsedDrv->useUidRange() && (!buildUser || buildUser->getUIDCount() < 65536))
+ throw Error("feature 'uid-range' requires the setting '%s' to be enabled", settings.autoAllocateUids.name);
+
+ /* Create /etc/hosts with localhost entry. */
+ if (derivationType->isSandboxed())
+ writeFile(chrootRootDir + "/etc/hosts", "127.0.0.1 localhost\n::1 localhost\n");
+
+ /* Make the closure of the inputs available in the chroot,
+ rather than the whole Nix store. This prevents any access
+ to undeclared dependencies. Directories are bind-mounted,
+ while other inputs are hard-linked (since only directories
+ can be bind-mounted). !!! As an extra security
+ precaution, make the fake Nix store only writable by the
+ build user. */
+ Path chrootStoreDir = chrootRootDir + worker.store.storeDir;
+ createDirs(chrootStoreDir);
+ chmodPath(chrootStoreDir, 01775);
+
+ if (buildUser && chown(chrootStoreDir.c_str(), 0, buildUser->getGID()) == -1)
+ throw SysError("cannot change ownership of '%1%'", chrootStoreDir);
+
+ for (auto & i : inputPaths) {
+ auto p = worker.store.printStorePath(i);
+ Path r = worker.store.toRealPath(p);
+ pathsInChroot.insert_or_assign(p, r);
+ }
+
+ /* If we're repairing, checking or rebuilding part of a
+ multiple-outputs derivation, it's possible that we're
+ rebuilding a path that is in settings.sandbox-paths
+ (typically the dependencies of /bin/sh). Throw them
+ out. */
+ for (auto & i : drv->outputsAndOptPaths(worker.store)) {
+ /* If the name isn't known a priori (i.e. floating
+ content-addressed derivation), the temporary location we use
+ should be fresh. Freshness means it is impossible that the path
+ is already in the sandbox, so we don't need to worry about
+ removing it. */
+ if (i.second.second)
+ pathsInChroot.erase(worker.store.printStorePath(*i.second.second));
+ }
+
+ if (cgroup) {
+ if (mkdir(cgroup->c_str(), 0755) != 0)
+ throw SysError("creating cgroup '%s'", *cgroup);
+ chownToBuilder(*cgroup);
+ chownToBuilder(*cgroup + "/cgroup.procs");
+ chownToBuilder(*cgroup + "/cgroup.threads");
+ //chownToBuilder(*cgroup + "/cgroup.subtree_control");
+ }
+}
+
void LinuxLocalDerivationGoal::killSandbox(bool getStats)
{
if (cgroup) {
diff --git a/src/libstore/platform/linux.hh b/src/libstore/platform/linux.hh
index 2cad001ea..7ef578d2c 100644
--- a/src/libstore/platform/linux.hh
+++ b/src/libstore/platform/linux.hh
@@ -42,7 +42,23 @@ public:
using LocalDerivationGoal::LocalDerivationGoal;
private:
+ /**
+ * Create and populate chroot
+ */
+ void prepareSandbox() override;
+
+ /**
+ * Kill all processes by build user, possibly using a reused
+ * cgroup if we have one
+ */
void killSandbox(bool getStatus) override;
+
+
+ bool supportsUidRange() override
+ {
+ return true;
+ }
+
};
}