Use vfork
This commit is contained in:
parent
b5ed5b6e66
commit
0e8fc118b3
3 changed files with 39 additions and 11 deletions
|
@ -863,31 +863,46 @@ void killUser(uid_t uid)
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
pid_t startProcess(std::function<void()> fun,
|
/* Wrapper around vfork to prevent the child process from clobbering
|
||||||
bool dieWithParent, const string & errorPrefix, bool runExitHandlers)
|
the caller's stack frame in the parent. */
|
||||||
|
static pid_t doFork(bool allowVfork, std::function<void()> fun) __attribute__((noinline));
|
||||||
|
static pid_t doFork(bool allowVfork, std::function<void()> fun)
|
||||||
{
|
{
|
||||||
|
#ifdef __linux__
|
||||||
|
pid_t pid = allowVfork ? vfork() : fork();
|
||||||
|
#else
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if (pid == -1) throw SysError("unable to fork");
|
#endif
|
||||||
|
if (pid != 0) return pid;
|
||||||
|
fun();
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
if (pid == 0) {
|
|
||||||
|
pid_t startProcess(std::function<void()> fun, const ProcessOptions & options)
|
||||||
|
{
|
||||||
|
auto wrapper = [&]() {
|
||||||
_writeToStderr = 0;
|
_writeToStderr = 0;
|
||||||
try {
|
try {
|
||||||
#if __linux__
|
#if __linux__
|
||||||
if (dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1)
|
if (options.dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1)
|
||||||
throw SysError("setting death signal");
|
throw SysError("setting death signal");
|
||||||
#endif
|
#endif
|
||||||
restoreAffinity();
|
restoreAffinity();
|
||||||
fun();
|
fun();
|
||||||
} catch (std::exception & e) {
|
} catch (std::exception & e) {
|
||||||
try {
|
try {
|
||||||
std::cerr << errorPrefix << e.what() << "\n";
|
std::cerr << options.errorPrefix << e.what() << "\n";
|
||||||
} catch (...) { }
|
} catch (...) { }
|
||||||
} catch (...) { }
|
} catch (...) { }
|
||||||
if (runExitHandlers)
|
if (options.runExitHandlers)
|
||||||
exit(1);
|
exit(1);
|
||||||
else
|
else
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
pid_t pid = doFork(options.allowVfork, wrapper);
|
||||||
|
if (pid == -1) throw SysError("unable to fork");
|
||||||
|
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,8 +269,16 @@ void killUser(uid_t uid);
|
||||||
|
|
||||||
/* Fork a process that runs the given function, and return the child
|
/* Fork a process that runs the given function, and return the child
|
||||||
pid to the caller. */
|
pid to the caller. */
|
||||||
pid_t startProcess(std::function<void()> fun, bool dieWithParent = true,
|
struct ProcessOptions
|
||||||
const string & errorPrefix = "error: ", bool runExitHandlers = false);
|
{
|
||||||
|
string errorPrefix;
|
||||||
|
bool dieWithParent;
|
||||||
|
bool runExitHandlers;
|
||||||
|
bool allowVfork;
|
||||||
|
ProcessOptions() : errorPrefix("error: "), dieWithParent(true), runExitHandlers(false), allowVfork(true) { };
|
||||||
|
};
|
||||||
|
|
||||||
|
pid_t startProcess(std::function<void()> fun, const ProcessOptions & options = ProcessOptions());
|
||||||
|
|
||||||
|
|
||||||
/* Run a program and return its stdout in a string (i.e., like the
|
/* Run a program and return its stdout in a string (i.e., like the
|
||||||
|
|
|
@ -799,6 +799,11 @@ static void daemonLoop(char * * argv)
|
||||||
% (peer.uidKnown ? user : "<unknown>"));
|
% (peer.uidKnown ? user : "<unknown>"));
|
||||||
|
|
||||||
/* Fork a child to handle the connection. */
|
/* Fork a child to handle the connection. */
|
||||||
|
ProcessOptions options;
|
||||||
|
options.errorPrefix = "unexpected Nix daemon error: ";
|
||||||
|
options.dieWithParent = false;
|
||||||
|
options.runExitHandlers = true;
|
||||||
|
options.allowVfork = false;
|
||||||
startProcess([&]() {
|
startProcess([&]() {
|
||||||
fdSocket.close();
|
fdSocket.close();
|
||||||
|
|
||||||
|
@ -821,7 +826,7 @@ static void daemonLoop(char * * argv)
|
||||||
processConnection(trusted);
|
processConnection(trusted);
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}, false, "unexpected Nix daemon error: ", true);
|
}, options);
|
||||||
|
|
||||||
} catch (Interrupted & e) {
|
} catch (Interrupted & e) {
|
||||||
throw;
|
throw;
|
||||||
|
|
Loading…
Reference in a new issue