Chromium Code Reviews| Index: content/zygote/zygote_linux.cc |
| diff --git a/content/zygote/zygote_linux.cc b/content/zygote/zygote_linux.cc |
| index 5944f87aa1258dff7a908eb6d5a2d55cea93a05f..c9e042f274bfe90242b5bcf7e8cc2db09542b1c3 100644 |
| --- a/content/zygote/zygote_linux.cc |
| +++ b/content/zygote/zygote_linux.cc |
| @@ -36,6 +36,8 @@ |
| #include "content/public/common/zygote_fork_delegate_linux.h" |
| #include "ipc/ipc_channel.h" |
| #include "ipc/ipc_switches.h" |
| +#include "sandbox/linux/services/credentials.h" |
| +#include "sandbox/linux/services/namespace_sandbox.h" |
| // See http://code.google.com/p/chromium/wiki/LinuxZygote |
| @@ -47,6 +49,14 @@ namespace { |
| void SIGCHLDHandler(int signal) { |
| } |
| +// On Linux, when a process is the init process of a PID namespace, it cannot be |
| +// terminated by signals like SIGTERM or SIGINT, since they are ignored unless |
| +// we register a handler for them. In the handlers, we exit with this special |
| +// exit code that GetTerminationStatus understands to mean that we were |
| +// terminated by an external signal. |
| +const int kKilledExitCode = 0x80; |
| +const int kUnexpectedExitCode = 0x81; |
| + |
| int LookUpFd(const base::GlobalDescriptors::Mapping& fd_mapping, uint32_t key) { |
| for (size_t index = 0; index < fd_mapping.size(); ++index) { |
| if (fd_mapping[index].key == key) |
| @@ -305,6 +315,11 @@ bool Zygote::GetTerminationStatus(base::ProcessHandle real_pid, |
| // Time to forget about this process. |
| process_info_map_.erase(real_pid); |
| } |
| + |
| + if (WIFEXITED(*exit_code) && WEXITSTATUS(*exit_code) == kKilledExitCode) { |
| + *status = base::TERMINATION_STATUS_PROCESS_WAS_KILLED; |
| + } |
| + |
| return true; |
| } |
| @@ -375,12 +390,32 @@ int Zygote::ForkWithRealPid(const std::string& process_type, |
| CHECK_NE(pid, 0); |
| } else { |
| CreatePipe(&read_pipe, &write_pipe); |
| - // This is roughly equivalent to a fork(). We are using ForkWithFlags mainly |
| - // to give it some more diverse test coverage. |
| - pid = base::ForkWithFlags(SIGCHLD, nullptr, nullptr); |
| + if (sandbox_flags_ & kSandboxLinuxPIDNS && |
| + sandbox_flags_ & kSandboxLinuxUserNS) { |
| + pid = sandbox::NamespaceSandbox::ForkInNewPidNamespace(true); |
|
jln (very slow on Chromium)
2015/03/25 23:47:50
/* drop_capabilities_in_child */
rickyz (no longer on Chrome)
2015/03/26 00:09:37
Done.
|
| + } else { |
| + pid = fork(); |
| + } |
| } |
| if (pid == 0) { |
| + // If the process is the init process inside a PID namespace, it must have |
| + // explicit signal handlers. |
| + if (getpid() == 1) { |
| + for (const int sig : {SIGINT, SIGTERM}) { |
| + sandbox::NamespaceSandbox::InstallTerminationSignalHandler( |
| + sig, kKilledExitCode); |
| + } |
| + |
| + static const int kUnexpectedSignals[] = { |
| + SIGHUP, SIGQUIT, SIGABRT, SIGPIPE, SIGUSR1, SIGUSR2, |
| + }; |
| + for (const int sig : kUnexpectedSignals) { |
| + sandbox::NamespaceSandbox::InstallTerminationSignalHandler( |
| + sig, kUnexpectedExitCode); |
| + } |
| + } |
| + |
| // In the child process. |
| write_pipe.reset(); |