aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/platform
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore/platform')
-rw-r--r--src/libstore/platform/darwin.hh6
-rw-r--r--src/libstore/platform/linux.cc88
-rw-r--r--src/libstore/platform/linux.hh16
3 files changed, 110 insertions, 0 deletions
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;
+ }
+
};
}