mirror of
https://github.com/NixOS/nix.git
synced 2025-11-11 13:06:01 +01:00
Open slave pseudoterminal before CLONE_NEWUSER
Otherwise, when running as root and user namespaces are enabled,
opening the slave fails with EPERM.
Fixes "opening pseudoterminal slave: Permission denied" followed by a
hang (https://hydra.nixos.org/build/213104244), and "error: getting
sandbox mount namespace: No such file or directory" (#8072), which
happens when the child fails very quickly and consequently reading
/proc/<child>/ns fails.
(cherry picked from commit 16db8dc96f)
This commit is contained in:
parent
94eba8a85a
commit
5fca88973f
1 changed files with 29 additions and 17 deletions
|
|
@ -454,7 +454,7 @@ static void commonChildInit(int stderrFd)
|
||||||
throw SysError(format("creating a new session"));
|
throw SysError(format("creating a new session"));
|
||||||
|
|
||||||
/* Dup the write side of the logger pipe into stderr. */
|
/* Dup the write side of the logger pipe into stderr. */
|
||||||
if (dup2(stderrFd, STDERR_FILENO) == -1)
|
if (stderrFd != -1 && dup2(stderrFd, STDERR_FILENO) == -1)
|
||||||
throw SysError("cannot pipe standard error into log file");
|
throw SysError("cannot pipe standard error into log file");
|
||||||
|
|
||||||
/* Dup stderr to stdout. */
|
/* Dup stderr to stdout. */
|
||||||
|
|
@ -2264,6 +2264,27 @@ void DerivationGoal::startBuilder()
|
||||||
if (unlockpt(builderOut.get()))
|
if (unlockpt(builderOut.get()))
|
||||||
throw SysError("unlocking pseudoterminal");
|
throw SysError("unlocking pseudoterminal");
|
||||||
|
|
||||||
|
/* Open the slave side of the pseudoterminal and use it as stderr. */
|
||||||
|
auto openSlave = [&]()
|
||||||
|
{
|
||||||
|
AutoCloseFD builderOut = open(slaveName.c_str(), O_RDWR | O_NOCTTY);
|
||||||
|
if (!builderOut)
|
||||||
|
throw SysError("opening pseudoterminal slave");
|
||||||
|
|
||||||
|
// Put the pt into raw mode to prevent \n -> \r\n translation.
|
||||||
|
struct termios term;
|
||||||
|
if (tcgetattr(builderOut.get(), &term))
|
||||||
|
throw SysError("getting pseudoterminal attributes");
|
||||||
|
|
||||||
|
cfmakeraw(&term);
|
||||||
|
|
||||||
|
if (tcsetattr(builderOut.get(), TCSANOW, &term))
|
||||||
|
throw SysError("putting pseudoterminal into raw mode");
|
||||||
|
|
||||||
|
if (dup2(builderOut.get(), STDERR_FILENO) == -1)
|
||||||
|
throw SysError("cannot pipe standard error into log file");
|
||||||
|
};
|
||||||
|
|
||||||
result.startTime = time(0);
|
result.startTime = time(0);
|
||||||
|
|
||||||
/* Fork a child to build the package. */
|
/* Fork a child to build the package. */
|
||||||
|
|
@ -2318,6 +2339,11 @@ void DerivationGoal::startBuilder()
|
||||||
Pid helper = startProcess([&]() {
|
Pid helper = startProcess([&]() {
|
||||||
sendPid.readSide.close();
|
sendPid.readSide.close();
|
||||||
|
|
||||||
|
/* We need to open the slave early, before
|
||||||
|
CLONE_NEWUSER. Otherwise we get EPERM when running as
|
||||||
|
root. */
|
||||||
|
openSlave();
|
||||||
|
|
||||||
/* Drop additional groups here because we can't do it
|
/* Drop additional groups here because we can't do it
|
||||||
after we've created the new user namespace. FIXME:
|
after we've created the new user namespace. FIXME:
|
||||||
this means that if we're not root in the parent
|
this means that if we're not root in the parent
|
||||||
|
|
@ -2410,6 +2436,7 @@ void DerivationGoal::startBuilder()
|
||||||
fallback:
|
fallback:
|
||||||
options.allowVfork = !buildUser && !drv->isBuiltin();
|
options.allowVfork = !buildUser && !drv->isBuiltin();
|
||||||
pid = startProcess([&]() {
|
pid = startProcess([&]() {
|
||||||
|
openSlave();
|
||||||
runChild();
|
runChild();
|
||||||
}, options);
|
}, options);
|
||||||
}
|
}
|
||||||
|
|
@ -2723,22 +2750,7 @@ void DerivationGoal::runChild()
|
||||||
|
|
||||||
try { /* child */
|
try { /* child */
|
||||||
|
|
||||||
/* Open the slave side of the pseudoterminal. */
|
commonChildInit(-1);
|
||||||
AutoCloseFD builderOut = open(slaveName.c_str(), O_RDWR | O_NOCTTY);
|
|
||||||
if (!builderOut)
|
|
||||||
throw SysError("opening pseudoterminal slave");
|
|
||||||
|
|
||||||
// Put the pt into raw mode to prevent \n -> \r\n translation.
|
|
||||||
struct termios term;
|
|
||||||
if (tcgetattr(builderOut.get(), &term))
|
|
||||||
throw SysError("getting pseudoterminal attributes");
|
|
||||||
|
|
||||||
cfmakeraw(&term);
|
|
||||||
|
|
||||||
if (tcsetattr(builderOut.get(), TCSANOW, &term))
|
|
||||||
throw SysError("putting pseudoterminal into raw mode");
|
|
||||||
|
|
||||||
commonChildInit(builderOut.get());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setupSeccomp();
|
setupSeccomp();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue