mirror of
https://github.com/NixOS/nix.git
synced 2024-11-21 22:32:26 +00:00
Propagate errors from early sandbox initialization to the parent
This should help with issues like https://github.com/DeterminateSystems/nix-installer/issues/1227, which currently just print "unable to start build process".
This commit is contained in:
parent
26c3fc11ea
commit
0be70469dc
@ -433,6 +433,41 @@ static void doBind(const Path & source, const Path & target, bool optional = fal
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rethrow the current exception as a subclass of `Error`.
|
||||||
|
*/
|
||||||
|
static void rethrowExceptionAsError()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
throw;
|
||||||
|
} catch (Error &) {
|
||||||
|
throw;
|
||||||
|
} catch (std::exception & e) {
|
||||||
|
throw Error(e.what());
|
||||||
|
} catch (...) {
|
||||||
|
throw Error("unknown exception");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the current exception to the parent in the format expected by
|
||||||
|
* `LocalDerivationGoal::processSandboxSetupMessages()`.
|
||||||
|
*/
|
||||||
|
static void handleChildException(bool sendException)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
rethrowExceptionAsError();
|
||||||
|
} catch (Error & e) {
|
||||||
|
if (sendException) {
|
||||||
|
writeFull(STDERR_FILENO, "\1\n");
|
||||||
|
FdSink sink(STDERR_FILENO);
|
||||||
|
sink << e;
|
||||||
|
sink.flush();
|
||||||
|
} else
|
||||||
|
std::cerr << e.msg();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LocalDerivationGoal::startBuilder()
|
void LocalDerivationGoal::startBuilder()
|
||||||
{
|
{
|
||||||
if ((buildUser && buildUser->getUIDCount() != 1)
|
if ((buildUser && buildUser->getUIDCount() != 1)
|
||||||
@ -949,32 +984,40 @@ void LocalDerivationGoal::startBuilder()
|
|||||||
root. */
|
root. */
|
||||||
openSlave();
|
openSlave();
|
||||||
|
|
||||||
/* Drop additional groups here because we can't do it
|
try {
|
||||||
after we've created the new user namespace. */
|
/* Drop additional groups here because we can't do it
|
||||||
if (setgroups(0, 0) == -1) {
|
after we've created the new user namespace. */
|
||||||
if (errno != EPERM)
|
if (setgroups(0, 0) == -1) {
|
||||||
throw SysError("setgroups failed");
|
if (errno != EPERM)
|
||||||
if (settings.requireDropSupplementaryGroups)
|
throw SysError("setgroups failed");
|
||||||
throw Error("setgroups failed. Set the require-drop-supplementary-groups option to false to skip this step.");
|
if (settings.requireDropSupplementaryGroups)
|
||||||
|
throw Error("setgroups failed. Set the require-drop-supplementary-groups option to false to skip this step.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessOptions options;
|
||||||
|
options.cloneFlags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD;
|
||||||
|
if (privateNetwork)
|
||||||
|
options.cloneFlags |= CLONE_NEWNET;
|
||||||
|
if (usingUserNamespace)
|
||||||
|
options.cloneFlags |= CLONE_NEWUSER;
|
||||||
|
|
||||||
|
pid_t child = startProcess([&]() { runChild(); }, options);
|
||||||
|
|
||||||
|
writeFull(sendPid.writeSide.get(), fmt("%d\n", child));
|
||||||
|
_exit(0);
|
||||||
|
} catch (...) {
|
||||||
|
handleChildException(true);
|
||||||
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessOptions options;
|
|
||||||
options.cloneFlags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD;
|
|
||||||
if (privateNetwork)
|
|
||||||
options.cloneFlags |= CLONE_NEWNET;
|
|
||||||
if (usingUserNamespace)
|
|
||||||
options.cloneFlags |= CLONE_NEWUSER;
|
|
||||||
|
|
||||||
pid_t child = startProcess([&]() { runChild(); }, options);
|
|
||||||
|
|
||||||
writeFull(sendPid.writeSide.get(), fmt("%d\n", child));
|
|
||||||
_exit(0);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
sendPid.writeSide.close();
|
sendPid.writeSide.close();
|
||||||
|
|
||||||
if (helper.wait() != 0)
|
if (helper.wait() != 0) {
|
||||||
|
processSandboxSetupMessages();
|
||||||
|
// Only reached if the child process didn't send an exception.
|
||||||
throw Error("unable to start build process");
|
throw Error("unable to start build process");
|
||||||
|
}
|
||||||
|
|
||||||
userNamespaceSync.readSide = -1;
|
userNamespaceSync.readSide = -1;
|
||||||
|
|
||||||
@ -1050,7 +1093,12 @@ void LocalDerivationGoal::startBuilder()
|
|||||||
pid.setSeparatePG(true);
|
pid.setSeparatePG(true);
|
||||||
worker.childStarted(shared_from_this(), {builderOut.get()}, true, true);
|
worker.childStarted(shared_from_this(), {builderOut.get()}, true, true);
|
||||||
|
|
||||||
/* Check if setting up the build environment failed. */
|
processSandboxSetupMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LocalDerivationGoal::processSandboxSetupMessages()
|
||||||
|
{
|
||||||
std::vector<std::string> msgs;
|
std::vector<std::string> msgs;
|
||||||
while (true) {
|
while (true) {
|
||||||
std::string msg = [&]() {
|
std::string msg = [&]() {
|
||||||
@ -1078,7 +1126,8 @@ void LocalDerivationGoal::startBuilder()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LocalDerivationGoal::initTmpDir() {
|
void LocalDerivationGoal::initTmpDir()
|
||||||
|
{
|
||||||
/* In a sandbox, for determinism, always use the same temporary
|
/* In a sandbox, for determinism, always use the same temporary
|
||||||
directory. */
|
directory. */
|
||||||
#if __linux__
|
#if __linux__
|
||||||
@ -2237,14 +2286,8 @@ void LocalDerivationGoal::runChild()
|
|||||||
|
|
||||||
throw SysError("executing '%1%'", drv->builder);
|
throw SysError("executing '%1%'", drv->builder);
|
||||||
|
|
||||||
} catch (Error & e) {
|
} catch (...) {
|
||||||
if (sendException) {
|
handleChildException(sendException);
|
||||||
writeFull(STDERR_FILENO, "\1\n");
|
|
||||||
FdSink sink(STDERR_FILENO);
|
|
||||||
sink << e;
|
|
||||||
sink.flush();
|
|
||||||
} else
|
|
||||||
std::cerr << e.msg();
|
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,6 +210,11 @@ struct LocalDerivationGoal : public DerivationGoal
|
|||||||
*/
|
*/
|
||||||
void initEnv();
|
void initEnv();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process messages send by the sandbox initialization.
|
||||||
|
*/
|
||||||
|
void processSandboxSetupMessages();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup tmp dir location.
|
* Setup tmp dir location.
|
||||||
*/
|
*/
|
||||||
|
@ -9,7 +9,7 @@ needLocalStore "The test uses --store always so we would just be bypassing the d
|
|||||||
|
|
||||||
TODO_NixOS
|
TODO_NixOS
|
||||||
|
|
||||||
unshare --mount --map-root-user bash <<EOF
|
unshare --mount --map-root-user -- bash -e -x <<EOF
|
||||||
source common.sh
|
source common.sh
|
||||||
|
|
||||||
# Avoid store dir being inside sandbox build-dir
|
# Avoid store dir being inside sandbox build-dir
|
||||||
@ -24,15 +24,13 @@ unshare --mount --map-root-user bash <<EOF
|
|||||||
cmd=(nix-build ./hermetic.nix --arg busybox "$busybox" --arg seed 1 --no-out-link)
|
cmd=(nix-build ./hermetic.nix --arg busybox "$busybox" --arg seed 1 --no-out-link)
|
||||||
|
|
||||||
# Fails with default setting
|
# Fails with default setting
|
||||||
# TODO better error
|
|
||||||
setLocalStore store1
|
setLocalStore store1
|
||||||
expectStderr 1 "\${cmd[@]}" | grepQuiet "unable to start build process"
|
expectStderr 1 "\${cmd[@]}" | grepQuiet "setgroups failed"
|
||||||
|
|
||||||
# Fails with `require-drop-supplementary-groups`
|
# Fails with `require-drop-supplementary-groups`
|
||||||
# TODO better error
|
|
||||||
setLocalStore store2
|
setLocalStore store2
|
||||||
NIX_CONFIG='require-drop-supplementary-groups = true' \
|
NIX_CONFIG='require-drop-supplementary-groups = true' \
|
||||||
expectStderr 1 "\${cmd[@]}" | grepQuiet "unable to start build process"
|
expectStderr 1 "\${cmd[@]}" | grepQuiet "setgroups failed"
|
||||||
|
|
||||||
# Works without `require-drop-supplementary-groups`
|
# Works without `require-drop-supplementary-groups`
|
||||||
setLocalStore store3
|
setLocalStore store3
|
||||||
|
Loading…
Reference in New Issue
Block a user