libstore: fix linux sandbox parent death signal handling

setting the signal is not enough, we must also check that the process we
expect to be parent to actually *is* our parent, not another process (eg
init if the daemon exited). we also have to set the death signal *after*
all set[ug]id calls, otherwise it will be cleared again by such changes.

Change-Id: I4e8c9102ea407576ed85b3203c8bb9bfb56762de
This commit is contained in:
eldritch horrors
2026-02-02 14:20:54 +00:00
parent 61e57329eb
commit dd54f45bc7
2 changed files with 20 additions and 13 deletions
+11 -13
View File
@@ -1518,6 +1518,16 @@ bool LinuxLocalDerivationGoal::prepareChildSetup()
return false;
}
void LinuxLocalDerivationGoal::finishChildSetup()
{
if (prctl(PR_SET_PDEATHSIG, SIGKILL) == -1) {
throw SysError("setting death signal");
}
if (getppid() != parentPid) {
raise(SIGKILL);
}
}
Pid LinuxLocalDerivationGoal::startChild(
const Path & builder, const Strings & envStrs, const Strings & args, AutoCloseFD logPTY
)
@@ -1660,10 +1670,6 @@ Pid LinuxLocalDerivationGoal::startChild(
}
return inVFork(/* flags*/ 0, [&]() {
if (prctl(PR_SET_PDEATHSIG, SIGKILL) == -1) {
throw SysError("setting death signal");
}
if (dup2(logPTY.get(), STDERR_FILENO) == -1) {
throw SysError("failed to redirect build output to log file");
}
@@ -1698,15 +1704,7 @@ Pid LinuxLocalDerivationGoal::startChild(
options.cloneFlags =
CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD;
return startProcess(
[&]() {
if (prctl(PR_SET_PDEATHSIG, SIGKILL) == -1) {
throw SysError("setting death signal");
}
runChild(builder, envStrs, args);
},
options
);
return startProcess([&]() { runChild(builder, envStrs, args); }, options);
});
}
+9
View File
@@ -5,6 +5,7 @@
#include "lix/libstore/gc-store.hh"
#include "lix/libstore/local-store.hh"
#include "lix/libutil/processes.hh"
#include <unistd.h>
namespace nix {
@@ -58,6 +59,12 @@ private:
Pid pastaPid;
/**
* used to initialize the parent death signal of children without racing
* with the parent dying before we got around to setting a death signal.
*/
pid_t parentPid = getpid();
/**
* Create a special accessor that can access paths that were built within the sandbox's
* chroot.
@@ -89,6 +96,8 @@ private:
bool prepareChildSetup() override;
void finishChildSetup() override;
std::string rewriteResolvConf(std::string fromHost);
/**