mirror of
https://github.com/NixOS/nix
synced 2025-06-25 10:41:16 +02:00
Eliminate useChroot
This commit is contained in:
parent
67408807d8
commit
9f8f3968e3
3 changed files with 155 additions and 101 deletions
|
@ -1,5 +1,15 @@
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
# include <spawn.h>
|
||||||
|
# include <sys/sysctl.h>
|
||||||
|
# include <sandbox.h>
|
||||||
|
|
||||||
|
/* This definition is undocumented but depended upon by all major browsers. */
|
||||||
|
extern "C" int
|
||||||
|
sandbox_init_with_parameters(const char * profile, uint64_t flags, const char * const parameters[], char ** errorbuf);
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
struct DarwinDerivationBuilder : DerivationBuilderImpl
|
struct DarwinDerivationBuilder : DerivationBuilderImpl
|
||||||
{
|
{
|
||||||
PathsInChroot pathsInChroot;
|
PathsInChroot pathsInChroot;
|
||||||
|
@ -185,4 +195,6 @@ struct DarwinDerivationBuilder : DerivationBuilderImpl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -52,15 +52,6 @@
|
||||||
# include "nix/store/personality.hh"
|
# include "nix/store/personality.hh"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
# include <spawn.h>
|
|
||||||
# include <sys/sysctl.h>
|
|
||||||
# include <sandbox.h>
|
|
||||||
|
|
||||||
/* This definition is undocumented but depended upon by all major browsers. */
|
|
||||||
extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -116,6 +107,7 @@ protected:
|
||||||
/**
|
/**
|
||||||
* The cgroup of the builder, if any.
|
* The cgroup of the builder, if any.
|
||||||
*/
|
*/
|
||||||
|
// FIXME: move
|
||||||
std::optional<Path> cgroup;
|
std::optional<Path> cgroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -134,18 +126,6 @@ protected:
|
||||||
*/
|
*/
|
||||||
Path tmpDirInSandbox;
|
Path tmpDirInSandbox;
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether we're currently doing a chroot build.
|
|
||||||
*/
|
|
||||||
// FIXME: remove
|
|
||||||
bool useChroot = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The root of the chroot environment.
|
|
||||||
*/
|
|
||||||
// FIXME: move
|
|
||||||
Path chrootRootDir;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RAII object to delete the chroot directory.
|
* RAII object to delete the chroot directory.
|
||||||
*/
|
*/
|
||||||
|
@ -250,6 +230,14 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire a build user lock. Return nullptr if no lock is available.
|
||||||
|
*/
|
||||||
|
virtual std::unique_ptr<UserLock> getBuildUser()
|
||||||
|
{
|
||||||
|
return acquireUserLock(1, false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the paths that should be made available in the sandbox.
|
* Return the paths that should be made available in the sandbox.
|
||||||
* This includes:
|
* This includes:
|
||||||
|
@ -261,12 +249,28 @@ protected:
|
||||||
*/
|
*/
|
||||||
PathsInChroot getPathsInSandbox();
|
PathsInChroot getPathsInSandbox();
|
||||||
|
|
||||||
|
virtual void setBuildTmpDir()
|
||||||
|
{
|
||||||
|
tmpDir = topTmpDir;
|
||||||
|
tmpDirInSandbox = topTmpDir;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by prepareBuild() to do any setup in the parent to
|
* Called by prepareBuild() to do any setup in the parent to
|
||||||
* prepare for a sandboxed build.
|
* prepare for a sandboxed build.
|
||||||
*/
|
*/
|
||||||
virtual void prepareSandbox();
|
virtual void prepareSandbox();
|
||||||
|
|
||||||
|
virtual Strings getPreBuildHookArgs()
|
||||||
|
{
|
||||||
|
return Strings({store.printStorePath(drvPath)});
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Path realPathInSandbox(const Path & p)
|
||||||
|
{
|
||||||
|
return store.toRealPath(p);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the slave side of the pseudoterminal and use it as stderr.
|
* Open the slave side of the pseudoterminal and use it as stderr.
|
||||||
*/
|
*/
|
||||||
|
@ -370,9 +374,13 @@ public:
|
||||||
|
|
||||||
void killSandbox(bool getStats) override;
|
void killSandbox(bool getStats) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual void cleanupBuild();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool cleanupDecideWhetherDiskFull();
|
bool decideWhetherDiskFull();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create alternative path calculated from but distinct from the
|
* Create alternative path calculated from but distinct from the
|
||||||
|
@ -462,12 +470,11 @@ bool DerivationBuilderImpl::prepareBuild()
|
||||||
{
|
{
|
||||||
if (useBuildUsers()) {
|
if (useBuildUsers()) {
|
||||||
if (!buildUser)
|
if (!buildUser)
|
||||||
buildUser = acquireUserLock(drvOptions.useUidRange(drv) ? 65536 : 1, useChroot);
|
buildUser = getBuildUser();
|
||||||
|
|
||||||
if (!buildUser) {
|
if (!buildUser)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -528,7 +535,9 @@ std::variant<std::pair<BuildResult::Status, Error>, SingleDrvOutputs> Derivation
|
||||||
/* Check the exit status. */
|
/* Check the exit status. */
|
||||||
if (!statusOk(status)) {
|
if (!statusOk(status)) {
|
||||||
|
|
||||||
diskFull |= cleanupDecideWhetherDiskFull();
|
diskFull |= decideWhetherDiskFull();
|
||||||
|
|
||||||
|
cleanupBuild();
|
||||||
|
|
||||||
auto msg = fmt(
|
auto msg = fmt(
|
||||||
"Cannot build '%s'.\n"
|
"Cannot build '%s'.\n"
|
||||||
|
@ -582,6 +591,10 @@ std::variant<std::pair<BuildResult::Status, Error>, SingleDrvOutputs> Derivation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DerivationBuilderImpl::cleanupBuild()
|
||||||
|
{
|
||||||
|
deleteTmpDir(false);
|
||||||
|
}
|
||||||
|
|
||||||
static void chmod_(const Path & path, mode_t mode)
|
static void chmod_(const Path & path, mode_t mode)
|
||||||
{
|
{
|
||||||
|
@ -644,10 +657,7 @@ static void replaceValidPath(const Path & storePath, const Path & tmpPath)
|
||||||
deletePath(oldPath);
|
deletePath(oldPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DerivationBuilderImpl::decideWhetherDiskFull()
|
||||||
|
|
||||||
|
|
||||||
bool DerivationBuilderImpl::cleanupDecideWhetherDiskFull()
|
|
||||||
{
|
{
|
||||||
bool diskFull = false;
|
bool diskFull = false;
|
||||||
|
|
||||||
|
@ -670,19 +680,6 @@ bool DerivationBuilderImpl::cleanupDecideWhetherDiskFull()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
deleteTmpDir(false);
|
|
||||||
|
|
||||||
/* Move paths out of the chroot for easier debugging of
|
|
||||||
build failures. */
|
|
||||||
if (useChroot && buildMode == bmNormal)
|
|
||||||
for (auto & [_, status] : initialOutputs) {
|
|
||||||
if (!status.known) continue;
|
|
||||||
if (buildMode != bmCheck && status.known->isValid()) continue;
|
|
||||||
auto p = store.toRealPath(status.known->path);
|
|
||||||
if (pathExists(chrootRootDir + p))
|
|
||||||
std::filesystem::rename((chrootRootDir + p), p);
|
|
||||||
}
|
|
||||||
|
|
||||||
return diskFull;
|
return diskFull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -832,23 +829,9 @@ void DerivationBuilderImpl::startBuilder()
|
||||||
/* Create a temporary directory where the build will take
|
/* Create a temporary directory where the build will take
|
||||||
place. */
|
place. */
|
||||||
topTmpDir = createTempDir(settings.buildDir.get().value_or(""), "nix-build-" + std::string(drvPath.name()), 0700);
|
topTmpDir = createTempDir(settings.buildDir.get().value_or(""), "nix-build-" + std::string(drvPath.name()), 0700);
|
||||||
#ifdef __APPLE__
|
setBuildTmpDir();
|
||||||
if (false) {
|
assert(!tmpDir.empty());
|
||||||
#else
|
assert(!tmpDirInSandbox.empty());
|
||||||
if (useChroot) {
|
|
||||||
#endif
|
|
||||||
/* If sandboxing is enabled, put the actual TMPDIR underneath
|
|
||||||
an inaccessible root-owned directory, to prevent outside
|
|
||||||
access.
|
|
||||||
|
|
||||||
On macOS, we don't use an actual chroot, so this isn't
|
|
||||||
possible. Any mitigation along these lines would have to be
|
|
||||||
done directly in the sandbox profile. */
|
|
||||||
tmpDir = topTmpDir + "/build";
|
|
||||||
createDir(tmpDir, 0700);
|
|
||||||
} else {
|
|
||||||
tmpDir = topTmpDir;
|
|
||||||
}
|
|
||||||
chownToBuilder(tmpDir);
|
chownToBuilder(tmpDir);
|
||||||
|
|
||||||
for (auto & [outputName, status] : initialOutputs) {
|
for (auto & [outputName, status] : initialOutputs) {
|
||||||
|
@ -1053,14 +1036,12 @@ DerivationBuilderImpl::PathsInChroot DerivationBuilderImpl::getPathsInSandbox()
|
||||||
|
|
||||||
if (settings.preBuildHook != "") {
|
if (settings.preBuildHook != "") {
|
||||||
printMsg(lvlChatty, "executing pre-build hook '%1%'", settings.preBuildHook);
|
printMsg(lvlChatty, "executing pre-build hook '%1%'", settings.preBuildHook);
|
||||||
auto args = useChroot ? Strings({store.printStorePath(drvPath), chrootRootDir}) :
|
|
||||||
Strings({ store.printStorePath(drvPath) });
|
|
||||||
enum BuildHookState {
|
enum BuildHookState {
|
||||||
stBegin,
|
stBegin,
|
||||||
stExtraChrootDirs
|
stExtraChrootDirs
|
||||||
};
|
};
|
||||||
auto state = stBegin;
|
auto state = stBegin;
|
||||||
auto lines = runProgram(settings.preBuildHook, false, args);
|
auto lines = runProgram(settings.preBuildHook, false, getPreBuildHookArgs());
|
||||||
auto lastPos = std::string::size_type{0};
|
auto lastPos = std::string::size_type{0};
|
||||||
for (auto nlPos = lines.find('\n'); nlPos != std::string::npos;
|
for (auto nlPos = lines.find('\n'); nlPos != std::string::npos;
|
||||||
nlPos = lines.find('\n', lastPos))
|
nlPos = lines.find('\n', lastPos))
|
||||||
|
@ -1157,14 +1138,6 @@ void DerivationBuilderImpl::processSandboxSetupMessages()
|
||||||
|
|
||||||
void DerivationBuilderImpl::initTmpDir()
|
void DerivationBuilderImpl::initTmpDir()
|
||||||
{
|
{
|
||||||
/* In a sandbox, for determinism, always use the same temporary
|
|
||||||
directory. */
|
|
||||||
#ifdef __linux__
|
|
||||||
tmpDirInSandbox = useChroot ? settings.sandboxBuildDir : tmpDir;
|
|
||||||
#else
|
|
||||||
tmpDirInSandbox = tmpDir;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* In non-structured mode, set all bindings either directory in the
|
/* In non-structured mode, set all bindings either directory in the
|
||||||
environment or via a file, as specified by
|
environment or via a file, as specified by
|
||||||
`DerivationOptions::passAsFile`. */
|
`DerivationOptions::passAsFile`. */
|
||||||
|
@ -1653,14 +1626,6 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
|
||||||
for (auto & i : scratchOutputs) referenceablePaths.insert(i.second);
|
for (auto & i : scratchOutputs) referenceablePaths.insert(i.second);
|
||||||
for (auto & p : addedPaths) referenceablePaths.insert(p);
|
for (auto & p : addedPaths) referenceablePaths.insert(p);
|
||||||
|
|
||||||
/* FIXME `needsHashRewrite` should probably be removed and we get to the
|
|
||||||
real reason why we aren't using the chroot dir */
|
|
||||||
auto toRealPathChroot = [&](const Path & p) -> Path {
|
|
||||||
return useChroot && !needsHashRewrite()
|
|
||||||
? chrootRootDir + p
|
|
||||||
: store.toRealPath(p);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Check whether the output paths were created, and make all
|
/* Check whether the output paths were created, and make all
|
||||||
output paths read-only. Then get the references of each output (that we
|
output paths read-only. Then get the references of each output (that we
|
||||||
might need to register), so we can topologically sort them. For the ones
|
might need to register), so we can topologically sort them. For the ones
|
||||||
|
@ -1677,7 +1642,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
|
||||||
throw BuildError(
|
throw BuildError(
|
||||||
"builder for '%s' has no scratch output for '%s'",
|
"builder for '%s' has no scratch output for '%s'",
|
||||||
store.printStorePath(drvPath), outputName);
|
store.printStorePath(drvPath), outputName);
|
||||||
auto actualPath = toRealPathChroot(store.printStorePath(*scratchOutput));
|
auto actualPath = realPathInSandbox(store.printStorePath(*scratchOutput));
|
||||||
|
|
||||||
outputsToSort.insert(outputName);
|
outputsToSort.insert(outputName);
|
||||||
|
|
||||||
|
@ -1786,7 +1751,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
|
||||||
auto output = get(drv.outputs, outputName);
|
auto output = get(drv.outputs, outputName);
|
||||||
auto scratchPath = get(scratchOutputs, outputName);
|
auto scratchPath = get(scratchOutputs, outputName);
|
||||||
assert(output && scratchPath);
|
assert(output && scratchPath);
|
||||||
auto actualPath = toRealPathChroot(store.printStorePath(*scratchPath));
|
auto actualPath = realPathInSandbox(store.printStorePath(*scratchPath));
|
||||||
|
|
||||||
auto finish = [&](StorePath finalStorePath) {
|
auto finish = [&](StorePath finalStorePath) {
|
||||||
/* Store the final path */
|
/* Store the final path */
|
||||||
|
@ -2361,10 +2326,14 @@ StorePath DerivationBuilderImpl::makeFallbackPath(const StorePath & path)
|
||||||
Hash(HashAlgorithm::SHA256), path.name());
|
Hash(HashAlgorithm::SHA256), path.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: do this properly
|
// FIXME: do this properly
|
||||||
#include "linux-derivation-builder.cc"
|
#include "linux-derivation-builder.cc"
|
||||||
#include "darwin-derivation-builder.cc"
|
#include "darwin-derivation-builder.cc"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
std::unique_ptr<DerivationBuilder> makeDerivationBuilder(
|
std::unique_ptr<DerivationBuilder> makeDerivationBuilder(
|
||||||
Store & store,
|
Store & store,
|
||||||
std::unique_ptr<DerivationBuilderCallbacks> miscMethods,
|
std::unique_ptr<DerivationBuilderCallbacks> miscMethods,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
struct LinuxDerivationBuilder : DerivationBuilderImpl
|
struct LinuxDerivationBuilder : DerivationBuilderImpl
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -20,23 +22,56 @@ struct LinuxDerivationBuilder : DerivationBuilderImpl
|
||||||
*/
|
*/
|
||||||
bool usingUserNamespace = true;
|
bool usingUserNamespace = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The root of the chroot environment.
|
||||||
|
*/
|
||||||
|
Path chrootRootDir;
|
||||||
|
|
||||||
PathsInChroot pathsInChroot;
|
PathsInChroot pathsInChroot;
|
||||||
|
|
||||||
LinuxDerivationBuilder(
|
LinuxDerivationBuilder(
|
||||||
Store & store, std::unique_ptr<DerivationBuilderCallbacks> miscMethods, DerivationBuilderParams params)
|
Store & store, std::unique_ptr<DerivationBuilderCallbacks> miscMethods, DerivationBuilderParams params)
|
||||||
: DerivationBuilderImpl(store, std::move(miscMethods), std::move(params))
|
: DerivationBuilderImpl(store, std::move(miscMethods), std::move(params))
|
||||||
{
|
{
|
||||||
useChroot = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uid_t sandboxUid() { return usingUserNamespace ? (!buildUser || buildUser->getUIDCount() == 1 ? 1000 : 0) : buildUser->getUID(); }
|
uid_t sandboxUid()
|
||||||
gid_t sandboxGid() { return usingUserNamespace ? (!buildUser || buildUser->getUIDCount() == 1 ? 100 : 0) : buildUser->getGID(); }
|
{
|
||||||
|
return usingUserNamespace ? (!buildUser || buildUser->getUIDCount() == 1 ? 1000 : 0) : buildUser->getUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
gid_t sandboxGid()
|
||||||
|
{
|
||||||
|
return usingUserNamespace ? (!buildUser || buildUser->getUIDCount() == 1 ? 100 : 0) : buildUser->getGID();
|
||||||
|
}
|
||||||
|
|
||||||
bool needsHashRewrite() override
|
bool needsHashRewrite() override
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<UserLock> getBuildUser() override
|
||||||
|
{
|
||||||
|
return acquireUserLock(drvOptions.useUidRange(drv) ? 65536 : 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBuildTmpDir() override
|
||||||
|
{
|
||||||
|
/* If sandboxing is enabled, put the actual TMPDIR underneath
|
||||||
|
an inaccessible root-owned directory, to prevent outside
|
||||||
|
access.
|
||||||
|
|
||||||
|
On macOS, we don't use an actual chroot, so this isn't
|
||||||
|
possible. Any mitigation along these lines would have to be
|
||||||
|
done directly in the sandbox profile. */
|
||||||
|
tmpDir = topTmpDir + "/build";
|
||||||
|
createDir(tmpDir, 0700);
|
||||||
|
|
||||||
|
/* In a sandbox, for determinism, always use the same temporary
|
||||||
|
directory. */
|
||||||
|
tmpDirInSandbox = settings.sandboxBuildDir;
|
||||||
|
}
|
||||||
|
|
||||||
void prepareSandbox() override
|
void prepareSandbox() override
|
||||||
{
|
{
|
||||||
/* Create a temporary directory in which we set up the chroot
|
/* Create a temporary directory in which we set up the chroot
|
||||||
|
@ -59,7 +94,10 @@ struct LinuxDerivationBuilder : DerivationBuilderImpl
|
||||||
if (mkdir(chrootRootDir.c_str(), buildUser && buildUser->getUIDCount() != 1 ? 0755 : 0750) == -1)
|
if (mkdir(chrootRootDir.c_str(), buildUser && buildUser->getUIDCount() != 1 ? 0755 : 0750) == -1)
|
||||||
throw SysError("cannot create '%1%'", chrootRootDir);
|
throw SysError("cannot create '%1%'", chrootRootDir);
|
||||||
|
|
||||||
if (buildUser && chown(chrootRootDir.c_str(), buildUser->getUIDCount() != 1 ? buildUser->getUID() : 0, buildUser->getGID()) == -1)
|
if (buildUser
|
||||||
|
&& chown(
|
||||||
|
chrootRootDir.c_str(), buildUser->getUIDCount() != 1 ? buildUser->getUID() : 0, buildUser->getGID())
|
||||||
|
== -1)
|
||||||
throw SysError("cannot change ownership of '%1%'", chrootRootDir);
|
throw SysError("cannot change ownership of '%1%'", chrootRootDir);
|
||||||
|
|
||||||
/* Create a writable /tmp in the chroot. Many builders need
|
/* Create a writable /tmp in the chroot. Many builders need
|
||||||
|
@ -81,10 +119,12 @@ struct LinuxDerivationBuilder : DerivationBuilderImpl
|
||||||
|
|
||||||
/* Declare the build user's group so that programs get a consistent
|
/* Declare the build user's group so that programs get a consistent
|
||||||
view of the system (e.g., "id -gn"). */
|
view of the system (e.g., "id -gn"). */
|
||||||
writeFile(chrootRootDir + "/etc/group",
|
writeFile(
|
||||||
|
chrootRootDir + "/etc/group",
|
||||||
fmt("root:x:0:\n"
|
fmt("root:x:0:\n"
|
||||||
"nixbld:!:%1%:\n"
|
"nixbld:!:%1%:\n"
|
||||||
"nogroup:x:65534:\n", sandboxGid()));
|
"nogroup:x:65534:\n",
|
||||||
|
sandboxGid()));
|
||||||
|
|
||||||
/* Create /etc/hosts with localhost entry. */
|
/* Create /etc/hosts with localhost entry. */
|
||||||
if (derivationType.isSandboxed())
|
if (derivationType.isSandboxed())
|
||||||
|
@ -125,7 +165,7 @@ struct LinuxDerivationBuilder : DerivationBuilderImpl
|
||||||
chownToBuilder(*cgroup);
|
chownToBuilder(*cgroup);
|
||||||
chownToBuilder(*cgroup + "/cgroup.procs");
|
chownToBuilder(*cgroup + "/cgroup.procs");
|
||||||
chownToBuilder(*cgroup + "/cgroup.threads");
|
chownToBuilder(*cgroup + "/cgroup.threads");
|
||||||
//chownToBuilder(*cgroup + "/cgroup.subtree_control");
|
// chownToBuilder(*cgroup + "/cgroup.subtree_control");
|
||||||
}
|
}
|
||||||
|
|
||||||
pathsInChroot = getPathsInSandbox();
|
pathsInChroot = getPathsInSandbox();
|
||||||
|
@ -136,6 +176,18 @@ struct LinuxDerivationBuilder : DerivationBuilderImpl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Strings getPreBuildHookArgs() override
|
||||||
|
{
|
||||||
|
assert(!chrootRootDir.empty());
|
||||||
|
return Strings({store.printStorePath(drvPath), chrootRootDir});
|
||||||
|
}
|
||||||
|
|
||||||
|
Path realPathInSandbox(const Path & p) override
|
||||||
|
{
|
||||||
|
// FIXME: why the needsHashRewrite() conditional?
|
||||||
|
return !needsHashRewrite() ? chrootRootDir + p : store.toRealPath(p);
|
||||||
|
}
|
||||||
|
|
||||||
void startChild() override
|
void startChild() override
|
||||||
{
|
{
|
||||||
/* Set up private namespaces for the build:
|
/* Set up private namespaces for the build:
|
||||||
|
@ -194,7 +246,8 @@ struct LinuxDerivationBuilder : DerivationBuilderImpl
|
||||||
if (errno != EPERM)
|
if (errno != EPERM)
|
||||||
throw SysError("setgroups failed");
|
throw SysError("setgroups failed");
|
||||||
if (settings.requireDropSupplementaryGroups)
|
if (settings.requireDropSupplementaryGroups)
|
||||||
throw Error("setgroups failed. Set the require-drop-supplementary-groups option to false to skip this step.");
|
throw Error(
|
||||||
|
"setgroups failed. Set the require-drop-supplementary-groups option to false to skip this step.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessOptions options;
|
ProcessOptions options;
|
||||||
|
@ -226,9 +279,7 @@ struct LinuxDerivationBuilder : DerivationBuilderImpl
|
||||||
|
|
||||||
/* Close the write side to prevent runChild() from hanging
|
/* Close the write side to prevent runChild() from hanging
|
||||||
reading from this. */
|
reading from this. */
|
||||||
Finally cleanup([&]() {
|
Finally cleanup([&]() { userNamespaceSync.writeSide = -1; });
|
||||||
userNamespaceSync.writeSide = -1;
|
|
||||||
});
|
|
||||||
|
|
||||||
auto ss = tokenizeString<std::vector<std::string>>(readLine(sendPid.readSide.get()));
|
auto ss = tokenizeString<std::vector<std::string>>(readLine(sendPid.readSide.get()));
|
||||||
assert(ss.size() == 1);
|
assert(ss.size() == 1);
|
||||||
|
@ -242,27 +293,29 @@ struct LinuxDerivationBuilder : DerivationBuilderImpl
|
||||||
uid_t hostGid = buildUser ? buildUser->getGID() : getgid();
|
uid_t hostGid = buildUser ? buildUser->getGID() : getgid();
|
||||||
uid_t nrIds = buildUser ? buildUser->getUIDCount() : 1;
|
uid_t nrIds = buildUser ? buildUser->getUIDCount() : 1;
|
||||||
|
|
||||||
writeFile("/proc/" + std::to_string(pid) + "/uid_map",
|
writeFile("/proc/" + std::to_string(pid) + "/uid_map", fmt("%d %d %d", sandboxUid(), hostUid, nrIds));
|
||||||
fmt("%d %d %d", sandboxUid(), hostUid, nrIds));
|
|
||||||
|
|
||||||
if (!buildUser || buildUser->getUIDCount() == 1)
|
if (!buildUser || buildUser->getUIDCount() == 1)
|
||||||
writeFile("/proc/" + std::to_string(pid) + "/setgroups", "deny");
|
writeFile("/proc/" + std::to_string(pid) + "/setgroups", "deny");
|
||||||
|
|
||||||
writeFile("/proc/" + std::to_string(pid) + "/gid_map",
|
writeFile("/proc/" + std::to_string(pid) + "/gid_map", fmt("%d %d %d", sandboxGid(), hostGid, nrIds));
|
||||||
fmt("%d %d %d", sandboxGid(), hostGid, nrIds));
|
|
||||||
} else {
|
} else {
|
||||||
debug("note: not using a user namespace");
|
debug("note: not using a user namespace");
|
||||||
if (!buildUser)
|
if (!buildUser)
|
||||||
throw Error("cannot perform a sandboxed build because user namespaces are not enabled; check /proc/sys/user/max_user_namespaces");
|
throw Error(
|
||||||
|
"cannot perform a sandboxed build because user namespaces are not enabled; check /proc/sys/user/max_user_namespaces");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now that we now the sandbox uid, we can write
|
/* Now that we now the sandbox uid, we can write
|
||||||
/etc/passwd. */
|
/etc/passwd. */
|
||||||
writeFile(chrootRootDir + "/etc/passwd", fmt(
|
writeFile(
|
||||||
"root:x:0:0:Nix build user:%3%:/noshell\n"
|
chrootRootDir + "/etc/passwd",
|
||||||
|
fmt("root:x:0:0:Nix build user:%3%:/noshell\n"
|
||||||
"nixbld:x:%1%:%2%:Nix build user:%3%:/noshell\n"
|
"nixbld:x:%1%:%2%:Nix build user:%3%:/noshell\n"
|
||||||
"nobody:x:65534:65534:Nobody:/:/noshell\n",
|
"nobody:x:65534:65534:Nobody:/:/noshell\n",
|
||||||
sandboxUid(), sandboxGid(), settings.sandboxBuildDir));
|
sandboxUid(),
|
||||||
|
sandboxGid(),
|
||||||
|
settings.sandboxBuildDir));
|
||||||
|
|
||||||
/* Save the mount- and user namespace of the child. We have to do this
|
/* Save the mount- and user namespace of the child. We have to do this
|
||||||
*before* the child does a chroot. */
|
*before* the child does a chroot. */
|
||||||
|
@ -528,6 +581,24 @@ struct LinuxDerivationBuilder : DerivationBuilderImpl
|
||||||
return DerivationBuilderImpl::unprepareBuild();
|
return DerivationBuilderImpl::unprepareBuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cleanupBuild() override
|
||||||
|
{
|
||||||
|
DerivationBuilderImpl::cleanupBuild();
|
||||||
|
|
||||||
|
/* Move paths out of the chroot for easier debugging of
|
||||||
|
build failures. */
|
||||||
|
if (buildMode == bmNormal)
|
||||||
|
for (auto & [_, status] : initialOutputs) {
|
||||||
|
if (!status.known)
|
||||||
|
continue;
|
||||||
|
if (buildMode != bmCheck && status.known->isValid())
|
||||||
|
continue;
|
||||||
|
auto p = store.toRealPath(status.known->path);
|
||||||
|
if (pathExists(chrootRootDir + p))
|
||||||
|
std::filesystem::rename((chrootRootDir + p), p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void addDependency(const StorePath & path) override
|
void addDependency(const StorePath & path) override
|
||||||
{
|
{
|
||||||
if (isAllowed(path))
|
if (isAllowed(path))
|
||||||
|
@ -568,4 +639,6 @@ struct LinuxDerivationBuilder : DerivationBuilderImpl
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue