Index: content/zygote/zygote_linux.cc |
diff --git a/content/zygote/zygote_linux.cc b/content/zygote/zygote_linux.cc |
index 8ac4a61d64e714920e501f28bf21736f625b6ced..e0dbbf7fa8f21629a08baa4b42397795d4d1770f 100644 |
--- a/content/zygote/zygote_linux.cc |
+++ b/content/zygote/zygote_linux.cc |
@@ -36,6 +36,7 @@ |
#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" |
#if defined(ADDRESS_SANITIZER) |
#include <sanitizer/asan_interface.h> |
@@ -51,6 +52,20 @@ 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; |
+ |
+void TerminationSignalHandler(int signal) { |
+ // Return a special exit code so that the process is detected as terminated by |
+ // a signal. We cannot terminate ourself with a signal since we may be the |
+ // init process in a PID namespace. |
+ _exit(kKilledExitCode); |
+} |
+ |
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) |
@@ -274,12 +289,10 @@ bool Zygote::GetTerminationStatus(base::ProcessHandle real_pid, |
bool known_dead, |
base::TerminationStatus* status, |
int* exit_code) { |
- |
ZygoteProcessInfo child_info; |
if (!GetProcessInfo(real_pid, &child_info)) { |
- LOG(ERROR) << "Zygote::GetTerminationStatus for unknown PID " |
+ LOG(FATAL) << "Zygote::GetTerminationStatus for unknown PID " |
<< real_pid; |
- NOTREACHED(); |
return false; |
} |
// We know about |real_pid|. |
@@ -304,6 +317,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; |
} |
@@ -374,12 +392,27 @@ 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); |
+ int clone_flags = SIGCHLD; |
+ if (sandbox_flags_ & kSandboxLinuxPIDNS && |
+ sandbox_flags_ & kSandboxLinuxUserNS) { |
+ clone_flags |= CLONE_NEWPID; |
+ } |
+ pid = base::ForkWithFlags(clone_flags, nullptr, nullptr); |
} |
if (pid == 0) { |
+ CHECK(sandbox::Credentials::DropAllCapabilities()); |
+ |
+ // If the process is the init process inside a PID namespace, it must have |
+ // explicit SIGTERM and SIGINT handlers. |
+ if (getpid() == 1) { |
+ struct sigaction action; |
+ memset(&action, 0, sizeof(action)); |
+ action.sa_handler = &TerminationSignalHandler; |
+ PCHECK(sigaction(SIGINT, &action, nullptr) == 0); |
+ PCHECK(sigaction(SIGTERM, &action, nullptr) == 0); |
+ } |
+ |
// In the child process. |
write_pipe.reset(); |