mirror of
https://github.com/NixOS/nix
synced 2025-07-07 18:31:49 +02:00
Bindmount files instead of hardlinking or copying to chroot
16591eb3cc (diff-19f999107b609d37cfb22c58e7f0bc1cf76edf1180e238dd6389e03cc279b604)
(2013) added support for files to doBind
This is work towards allowing users to change the location of chrootRootDir, to, for example, a tmpfs.
inspired by trofi on matrix
> It looks like build sandbox created by nix-daemon runs on the same filesystem, as /nix/store including things like /tmp which makes all small temporary files hit the disk. Is it intentional? If it is is there an easy way to redirect chroot's root to be tmpfs?
dirsInChroot -> pathsInChroot
This commit is contained in:
parent
b99fdcf8db
commit
5649229394
2 changed files with 23 additions and 45 deletions
|
@ -581,7 +581,7 @@ void LocalDerivationGoal::startBuilder()
|
||||||
|
|
||||||
/* Allow a user-configurable set of directories from the
|
/* Allow a user-configurable set of directories from the
|
||||||
host file system. */
|
host file system. */
|
||||||
dirsInChroot.clear();
|
pathsInChroot.clear();
|
||||||
|
|
||||||
for (auto i : settings.sandboxPaths.get()) {
|
for (auto i : settings.sandboxPaths.get()) {
|
||||||
if (i.empty()) continue;
|
if (i.empty()) continue;
|
||||||
|
@ -592,19 +592,19 @@ void LocalDerivationGoal::startBuilder()
|
||||||
}
|
}
|
||||||
size_t p = i.find('=');
|
size_t p = i.find('=');
|
||||||
if (p == std::string::npos)
|
if (p == std::string::npos)
|
||||||
dirsInChroot[i] = {i, optional};
|
pathsInChroot[i] = {i, optional};
|
||||||
else
|
else
|
||||||
dirsInChroot[i.substr(0, p)] = {i.substr(p + 1), optional};
|
pathsInChroot[i.substr(0, p)] = {i.substr(p + 1), optional};
|
||||||
}
|
}
|
||||||
if (hasPrefix(worker.store.storeDir, tmpDirInSandbox))
|
if (hasPrefix(worker.store.storeDir, tmpDirInSandbox))
|
||||||
{
|
{
|
||||||
throw Error("`sandbox-build-dir` must not contain the storeDir");
|
throw Error("`sandbox-build-dir` must not contain the storeDir");
|
||||||
}
|
}
|
||||||
dirsInChroot[tmpDirInSandbox] = tmpDir;
|
pathsInChroot[tmpDirInSandbox] = tmpDir;
|
||||||
|
|
||||||
/* Add the closure of store paths to the chroot. */
|
/* Add the closure of store paths to the chroot. */
|
||||||
StorePathSet closure;
|
StorePathSet closure;
|
||||||
for (auto & i : dirsInChroot)
|
for (auto & i : pathsInChroot)
|
||||||
try {
|
try {
|
||||||
if (worker.store.isInStore(i.second.source))
|
if (worker.store.isInStore(i.second.source))
|
||||||
worker.store.computeFSClosure(worker.store.toStorePath(i.second.source).first, closure);
|
worker.store.computeFSClosure(worker.store.toStorePath(i.second.source).first, closure);
|
||||||
|
@ -615,7 +615,7 @@ void LocalDerivationGoal::startBuilder()
|
||||||
}
|
}
|
||||||
for (auto & i : closure) {
|
for (auto & i : closure) {
|
||||||
auto p = worker.store.printStorePath(i);
|
auto p = worker.store.printStorePath(i);
|
||||||
dirsInChroot.insert_or_assign(p, p);
|
pathsInChroot.insert_or_assign(p, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathSet allowedPaths = settings.allowedImpureHostPrefixes;
|
PathSet allowedPaths = settings.allowedImpureHostPrefixes;
|
||||||
|
@ -643,7 +643,7 @@ void LocalDerivationGoal::startBuilder()
|
||||||
|
|
||||||
/* Allow files in __impureHostDeps to be missing; e.g.
|
/* Allow files in __impureHostDeps to be missing; e.g.
|
||||||
macOS 11+ has no /usr/lib/libSystem*.dylib */
|
macOS 11+ has no /usr/lib/libSystem*.dylib */
|
||||||
dirsInChroot[i] = {i, true};
|
pathsInChroot[i] = {i, true};
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __linux__
|
#if __linux__
|
||||||
|
@ -711,15 +711,12 @@ void LocalDerivationGoal::startBuilder()
|
||||||
for (auto & i : inputPaths) {
|
for (auto & i : inputPaths) {
|
||||||
auto p = worker.store.printStorePath(i);
|
auto p = worker.store.printStorePath(i);
|
||||||
Path r = worker.store.toRealPath(p);
|
Path r = worker.store.toRealPath(p);
|
||||||
if (S_ISDIR(lstat(r).st_mode))
|
pathsInChroot.insert_or_assign(p, r);
|
||||||
dirsInChroot.insert_or_assign(p, r);
|
|
||||||
else
|
|
||||||
linkOrCopy(r, chrootRootDir + p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we're repairing, checking or rebuilding part of a
|
/* If we're repairing, checking or rebuilding part of a
|
||||||
multiple-outputs derivation, it's possible that we're
|
multiple-outputs derivation, it's possible that we're
|
||||||
rebuilding a path that is in settings.dirsInChroot
|
rebuilding a path that is in settings.sandbox-paths
|
||||||
(typically the dependencies of /bin/sh). Throw them
|
(typically the dependencies of /bin/sh). Throw them
|
||||||
out. */
|
out. */
|
||||||
for (auto & i : drv->outputsAndOptPaths(worker.store)) {
|
for (auto & i : drv->outputsAndOptPaths(worker.store)) {
|
||||||
|
@ -729,7 +726,7 @@ void LocalDerivationGoal::startBuilder()
|
||||||
is already in the sandbox, so we don't need to worry about
|
is already in the sandbox, so we don't need to worry about
|
||||||
removing it. */
|
removing it. */
|
||||||
if (i.second.second)
|
if (i.second.second)
|
||||||
dirsInChroot.erase(worker.store.printStorePath(*i.second.second));
|
pathsInChroot.erase(worker.store.printStorePath(*i.second.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cgroup) {
|
if (cgroup) {
|
||||||
|
@ -787,9 +784,9 @@ void LocalDerivationGoal::startBuilder()
|
||||||
} else {
|
} else {
|
||||||
auto p = line.find('=');
|
auto p = line.find('=');
|
||||||
if (p == std::string::npos)
|
if (p == std::string::npos)
|
||||||
dirsInChroot[line] = line;
|
pathsInChroot[line] = line;
|
||||||
else
|
else
|
||||||
dirsInChroot[line.substr(0, p)] = line.substr(p + 1);
|
pathsInChroot[line.substr(0, p)] = line.substr(p + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1779,7 +1776,7 @@ void LocalDerivationGoal::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;
|
Strings ss;
|
||||||
if (dirsInChroot.find("/dev") == dirsInChroot.end()) {
|
if (pathsInChroot.find("/dev") == pathsInChroot.end()) {
|
||||||
createDirs(chrootRootDir + "/dev/shm");
|
createDirs(chrootRootDir + "/dev/shm");
|
||||||
createDirs(chrootRootDir + "/dev/pts");
|
createDirs(chrootRootDir + "/dev/pts");
|
||||||
ss.push_back("/dev/full");
|
ss.push_back("/dev/full");
|
||||||
|
@ -1814,34 +1811,15 @@ void LocalDerivationGoal::runChild()
|
||||||
ss.push_back(path);
|
ss.push_back(path);
|
||||||
|
|
||||||
if (settings.caFile != "")
|
if (settings.caFile != "")
|
||||||
dirsInChroot.try_emplace("/etc/ssl/certs/ca-certificates.crt", settings.caFile, true);
|
pathsInChroot.try_emplace("/etc/ssl/certs/ca-certificates.crt", settings.caFile, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto & i : ss) dirsInChroot.emplace(i, i);
|
for (auto & i : ss) pathsInChroot.emplace(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. */
|
||||||
auto doBind = [&](const Path & source, const Path & target, bool optional = false) {
|
for (auto & i : pathsInChroot) {
|
||||||
debug("bind mounting '%1%' to '%2%'", source, target);
|
|
||||||
struct stat st;
|
|
||||||
if (stat(source.c_str(), &st) == -1) {
|
|
||||||
if (optional && errno == ENOENT)
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
throw SysError("getting attributes of path '%1%'", source);
|
|
||||||
}
|
|
||||||
if (S_ISDIR(st.st_mode))
|
|
||||||
createDirs(target);
|
|
||||||
else {
|
|
||||||
createDirs(dirOf(target));
|
|
||||||
writeFile(target, "");
|
|
||||||
}
|
|
||||||
if (mount(source.c_str(), target.c_str(), "", MS_BIND | MS_REC, 0) == -1)
|
|
||||||
throw SysError("bind mount from '%1%' to '%2%' failed", source, target);
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto & i : dirsInChroot) {
|
|
||||||
if (i.second.source == "/proc") continue; // backwards compatibility
|
if (i.second.source == "/proc") continue; // backwards compatibility
|
||||||
|
|
||||||
#if HAVE_EMBEDDED_SANDBOX_SHELL
|
#if HAVE_EMBEDDED_SANDBOX_SHELL
|
||||||
|
@ -1882,7 +1860,7 @@ void LocalDerivationGoal::runChild()
|
||||||
if /dev/ptx/ptmx exists). */
|
if /dev/ptx/ptmx exists). */
|
||||||
if (pathExists("/dev/pts/ptmx") &&
|
if (pathExists("/dev/pts/ptmx") &&
|
||||||
!pathExists(chrootRootDir + "/dev/ptmx")
|
!pathExists(chrootRootDir + "/dev/ptmx")
|
||||||
&& !dirsInChroot.count("/dev/pts"))
|
&& !pathsInChroot.count("/dev/pts"))
|
||||||
{
|
{
|
||||||
if (mount("none", (chrootRootDir + "/dev/pts").c_str(), "devpts", 0, "newinstance,mode=0620") == 0)
|
if (mount("none", (chrootRootDir + "/dev/pts").c_str(), "devpts", 0, "newinstance,mode=0620") == 0)
|
||||||
{
|
{
|
||||||
|
@ -2017,7 +1995,7 @@ void LocalDerivationGoal::runChild()
|
||||||
/* We build the ancestry before adding all inputPaths to the store because we know they'll
|
/* We build the ancestry before adding all inputPaths to the store because we know they'll
|
||||||
all have the same parents (the store), and there might be lots of inputs. This isn't
|
all have the same parents (the store), and there might be lots of inputs. This isn't
|
||||||
particularly efficient... I doubt it'll be a bottleneck in practice */
|
particularly efficient... I doubt it'll be a bottleneck in practice */
|
||||||
for (auto & i : dirsInChroot) {
|
for (auto & i : pathsInChroot) {
|
||||||
Path cur = i.first;
|
Path cur = i.first;
|
||||||
while (cur.compare("/") != 0) {
|
while (cur.compare("/") != 0) {
|
||||||
cur = dirOf(cur);
|
cur = dirOf(cur);
|
||||||
|
@ -2025,7 +2003,7 @@ void LocalDerivationGoal::runChild()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* And we want the store in there regardless of how empty dirsInChroot. We include the innermost
|
/* And we want the store in there regardless of how empty pathsInChroot. We include the innermost
|
||||||
path component this time, since it's typically /nix/store and we care about that. */
|
path component this time, since it's typically /nix/store and we care about that. */
|
||||||
Path cur = worker.store.storeDir;
|
Path cur = worker.store.storeDir;
|
||||||
while (cur.compare("/") != 0) {
|
while (cur.compare("/") != 0) {
|
||||||
|
@ -2036,7 +2014,7 @@ void LocalDerivationGoal::runChild()
|
||||||
/* Add all our input paths to the chroot */
|
/* Add all our input paths to the chroot */
|
||||||
for (auto & i : inputPaths) {
|
for (auto & i : inputPaths) {
|
||||||
auto p = worker.store.printStorePath(i);
|
auto p = worker.store.printStorePath(i);
|
||||||
dirsInChroot[p] = p;
|
pathsInChroot[p] = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */
|
/* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */
|
||||||
|
@ -2067,7 +2045,7 @@ void LocalDerivationGoal::runChild()
|
||||||
without file-write* allowed, access() incorrectly returns EPERM
|
without file-write* allowed, access() incorrectly returns EPERM
|
||||||
*/
|
*/
|
||||||
sandboxProfile += "(allow file-read* file-write* process-exec\n";
|
sandboxProfile += "(allow file-read* file-write* process-exec\n";
|
||||||
for (auto & i : dirsInChroot) {
|
for (auto & i : pathsInChroot) {
|
||||||
if (i.first != i.second.source)
|
if (i.first != i.second.source)
|
||||||
throw Error(
|
throw Error(
|
||||||
"can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin",
|
"can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin",
|
||||||
|
|
|
@ -86,8 +86,8 @@ struct LocalDerivationGoal : public DerivationGoal
|
||||||
: source(source), optional(optional)
|
: source(source), optional(optional)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
typedef map<Path, ChrootPath> DirsInChroot; // maps target path to source path
|
typedef map<Path, ChrootPath> PathsInChroot; // maps target path to source path
|
||||||
DirsInChroot dirsInChroot;
|
PathsInChroot pathsInChroot;
|
||||||
|
|
||||||
typedef map<std::string, std::string> Environment;
|
typedef map<std::string, std::string> Environment;
|
||||||
Environment env;
|
Environment env;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue