diff options
author | Andras Becsi <andras.becsi@digia.com> | 2013-12-11 21:33:03 +0100 |
---|---|---|
committer | Andras Becsi <andras.becsi@digia.com> | 2013-12-13 12:34:07 +0100 |
commit | f2a33ff9cbc6d19943f1c7fbddd1f23d23975577 (patch) | |
tree | 0586a32aa390ade8557dfd6b4897f43a07449578 /chromium/content/zygote | |
parent | 5362912cdb5eea702b68ebe23702468d17c3017a (diff) | |
download | qtwebengine-chromium-f2a33ff9cbc6d19943f1c7fbddd1f23d23975577.tar.gz |
Update Chromium to branch 1650 (31.0.1650.63)
Change-Id: I57d8c832eaec1eb2364e0a8e7352a6dd354db99f
Reviewed-by: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
Diffstat (limited to 'chromium/content/zygote')
-rw-r--r-- | chromium/content/zygote/zygote_linux.cc | 136 | ||||
-rw-r--r-- | chromium/content/zygote/zygote_linux.h | 40 | ||||
-rw-r--r-- | chromium/content/zygote/zygote_main_linux.cc | 36 |
3 files changed, 147 insertions, 65 deletions
diff --git a/chromium/content/zygote/zygote_linux.cc b/chromium/content/zygote/zygote_linux.cc index abb52aea32c..08f1ecbb5d2 100644 --- a/chromium/content/zygote/zygote_linux.cc +++ b/chromium/content/zygote/zygote_linux.cc @@ -20,6 +20,7 @@ #include "base/posix/global_descriptors.h" #include "base/posix/unix_domain_socket_linux.h" #include "base/process/kill.h" +#include "content/common/child_process_sandbox_support_impl_linux.h" #include "content/common/sandbox_linux.h" #include "content/common/set_process_title.h" #include "content/common/zygote_commands_linux.h" @@ -42,8 +43,6 @@ void SIGCHLDHandler(int signal) { } // namespace -const int Zygote::kMagicSandboxIPCDescriptor; - Zygote::Zygote(int sandbox_flags, ZygoteForkDelegate* helper) : sandbox_flags_(sandbox_flags), @@ -77,7 +76,7 @@ bool Zygote::ProcessRequests() { // Let the ZygoteHost know we are ready to go. // The receiving code is in content/browser/zygote_host_linux.cc. std::vector<int> empty; - bool r = UnixDomainSocket::SendMsg(kBrowserDescriptor, + bool r = UnixDomainSocket::SendMsg(kZygoteSocketPairFd, kZygoteHelloMessage, sizeof(kZygoteHelloMessage), empty); #if defined(OS_CHROMEOS) @@ -94,11 +93,22 @@ bool Zygote::ProcessRequests() { for (;;) { // This function call can return multiple times, once per fork(). - if (HandleRequestFromBrowser(kBrowserDescriptor)) + if (HandleRequestFromBrowser(kZygoteSocketPairFd)) return true; } } +bool Zygote::GetProcessInfo(base::ProcessHandle pid, + ZygoteProcessInfo* process_info) { + DCHECK(process_info); + const ZygoteProcessMap::const_iterator it = process_info_map_.find(pid); + if (it == process_info_map_.end()) { + return false; + } + *process_info = it->second; + return true; +} + bool Zygote::UsingSUIDSandbox() const { return sandbox_flags_ & kSandboxLinuxSUID; } @@ -155,37 +165,87 @@ bool Zygote::HandleRequestFromBrowser(int fd) { return false; } +// TODO(jln): remove callers to this broken API. See crbug.com/274855. void Zygote::HandleReapRequest(int fd, const Pickle& pickle, PickleIterator iter) { base::ProcessId child; - base::ProcessId actual_child; if (!pickle.ReadInt(&iter, &child)) { LOG(WARNING) << "Error parsing reap request from browser"; return; } - if (UsingSUIDSandbox()) { - actual_child = real_pids_to_sandbox_pids[child]; - if (!actual_child) - return; - real_pids_to_sandbox_pids.erase(child); + ZygoteProcessInfo child_info; + if (!GetProcessInfo(child, &child_info)) { + LOG(ERROR) << "Child not found!"; + NOTREACHED(); + return; + } + + if (!child_info.started_from_helper) { + // TODO(jln): this old code is completely broken. See crbug.com/274855. + base::EnsureProcessTerminated(child_info.internal_pid); } else { - actual_child = child; + // For processes from the helper, send a GetTerminationStatus request + // with known_dead set to true. + // This is not perfect, as the process may be killed instantly, but is + // better than ignoring the request. + base::TerminationStatus status; + int exit_code; + bool got_termination_status = + GetTerminationStatus(child, true /* known_dead */, &status, &exit_code); + DCHECK(got_termination_status); } + process_info_map_.erase(child); +} + +bool Zygote::GetTerminationStatus(base::ProcessHandle real_pid, + bool known_dead, + base::TerminationStatus* status, + int* exit_code) { - base::EnsureProcessTerminated(actual_child); + ZygoteProcessInfo child_info; + if (!GetProcessInfo(real_pid, &child_info)) { + LOG(ERROR) << "Zygote::GetTerminationStatus for unknown PID " + << real_pid; + NOTREACHED(); + return false; + } + // We know about |real_pid|. + const base::ProcessHandle child = child_info.internal_pid; + if (child_info.started_from_helper) { + // Let the helper handle the request. + DCHECK(helper_); + if (!helper_->GetTerminationStatus(child, known_dead, status, exit_code)) { + return false; + } + } else { + // Handle the request directly. + if (known_dead) { + *status = base::GetKnownDeadTerminationStatus(child, exit_code); + } else { + // We don't know if the process is dying, so get its status but don't + // wait. + *status = base::GetTerminationStatus(child, exit_code); + } + } + // Successfully got a status for |real_pid|. + if (*status != base::TERMINATION_STATUS_STILL_RUNNING) { + // Time to forget about this process. + process_info_map_.erase(real_pid); + } + return true; } void Zygote::HandleGetTerminationStatus(int fd, const Pickle& pickle, PickleIterator iter) { bool known_dead; - base::ProcessHandle child; + base::ProcessHandle child_requested; if (!pickle.ReadBool(&iter, &known_dead) || - !pickle.ReadInt(&iter, &child)) { + !pickle.ReadInt(&iter, &child_requested)) { LOG(WARNING) << "Error parsing GetTerminationStatus request " << "from browser"; return; @@ -193,26 +253,13 @@ void Zygote::HandleGetTerminationStatus(int fd, base::TerminationStatus status; int exit_code; - if (UsingSUIDSandbox()) - child = real_pids_to_sandbox_pids[child]; - if (child) { - if (known_dead) { - // If we know that the process is already dead and the kernel is cleaning - // it up, we do want to wait until it becomes a zombie and not risk - // returning eroneously that it is still running. However, we do not - // want to risk a bug where we're told a process is dead when it's not. - // By sending SIGKILL, we make sure that WaitForTerminationStatus will - // return quickly even in this case. - if (kill(child, SIGKILL)) { - PLOG(ERROR) << "kill (" << child << ")"; - } - status = base::WaitForTerminationStatus(child, &exit_code); - } else { - status = base::GetTerminationStatus(child, &exit_code); - } - } else { + + bool got_termination_status = + GetTerminationStatus(child_requested, known_dead, &status, &exit_code); + if (!got_termination_status) { // Assume that if we can't find the child in the sandbox, then // it terminated normally. + NOTREACHED(); status = base::TERMINATION_STATUS_NORMAL_TERMINATION; exit_code = RESULT_CODE_NORMAL_EXIT; } @@ -236,10 +283,6 @@ int Zygote::ForkWithRealPid(const std::string& process_type, uma_name, uma_sample, uma_boundary_value)); - if (!(use_helper || UsingSUIDSandbox())) { - return fork(); - } - int dummy_fd; ino_t dummy_inode; int pipe_fds[2] = { -1, -1 }; @@ -310,7 +353,7 @@ int Zygote::ForkWithRealPid(const std::string& process_type, request.WriteUInt64(dummy_inode); const ssize_t r = UnixDomainSocket::SendRecvMsg( - kMagicSandboxIPCDescriptor, reply_buf, sizeof(reply_buf), NULL, + GetSandboxFD(), reply_buf, sizeof(reply_buf), NULL, request); if (r == -1) { LOG(ERROR) << "Failed to get child process's real PID"; @@ -326,10 +369,21 @@ int Zygote::ForkWithRealPid(const std::string& process_type, LOG(ERROR) << "METHOD_GET_CHILD_WITH_INODE failed"; goto error; } - real_pids_to_sandbox_pids[real_pid] = pid; + } else { + // If no SUID sandbox is involved then no pid translation is + // necessary. + real_pid = pid; } + + // Now set-up this process to be tracked by the Zygote. + if (process_info_map_.find(real_pid) != process_info_map_.end()) { + LOG(ERROR) << "Already tracking PID " << real_pid; + NOTREACHED(); + } + process_info_map_[real_pid].internal_pid = pid; + process_info_map_[real_pid].started_from_helper = use_helper; + if (use_helper) { - real_pid = pid; if (!helper_->AckChild(pipe_fds[1], channel_switch)) { LOG(ERROR) << "Failed to synchronise with zygote fork helper"; goto error; @@ -402,7 +456,7 @@ base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle, } mapping.push_back(std::make_pair( - static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor)); + static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD())); // Returns twice, once per process. base::ProcessId child_pid = ForkWithRealPid(process_type, fds, channel_id, @@ -411,7 +465,7 @@ base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle, if (!child_pid) { // This is the child process. - close(kBrowserDescriptor); // Our socket from the browser. + close(kZygoteSocketPairFd); // Our socket from the browser. if (UsingSUIDSandbox()) close(kZygoteIdFd); // Another socket from the browser. base::GlobalDescriptors::GetInstance()->Reset(mapping); diff --git a/chromium/content/zygote/zygote_linux.h b/chromium/content/zygote/zygote_linux.h index 3b175acd8a7..ffea49a0da1 100644 --- a/chromium/content/zygote/zygote_linux.h +++ b/chromium/content/zygote/zygote_linux.h @@ -8,7 +8,8 @@ #include <string> #include <vector> -#include "base/containers/hash_tables.h" +#include "base/containers/small_map.h" +#include "base/process/kill.h" #include "base/process/process.h" class Pickle; @@ -29,10 +30,23 @@ class Zygote { bool ProcessRequests(); - static const int kBrowserDescriptor = 3; - static const int kMagicSandboxIPCDescriptor = 5; - private: + struct ZygoteProcessInfo { + // Pid from inside the Zygote's PID namespace. + base::ProcessHandle internal_pid; + // Keeps track of whether or not a process was started from a fork + // delegate helper. + bool started_from_helper; + }; + typedef base::SmallMap< std::map<base::ProcessHandle, ZygoteProcessInfo> > + ZygoteProcessMap; + + // Retrieve a ZygoteProcessInfo from the process_info_map_. + // Returns true and write to process_info if |pid| can be found, return + // false otherwise. + bool GetProcessInfo(base::ProcessHandle pid, + ZygoteProcessInfo* process_info); + // Returns true if the SUID sandbox is active. bool UsingSUIDSandbox() const; @@ -45,6 +59,14 @@ class Zygote { void HandleReapRequest(int fd, const Pickle& pickle, PickleIterator iter); + // Get the termination status of |real_pid|. |real_pid| is the PID as it + // appears outside of the sandbox. + // Return true if it managed to get the termination status and return the + // status in |status| and the exit code in |exit_code|. + bool GetTerminationStatus(base::ProcessHandle real_pid, bool known_dead, + base::TerminationStatus* status, + int* exit_code); + void HandleGetTerminationStatus(int fd, const Pickle& pickle, PickleIterator iter); @@ -84,11 +106,11 @@ class Zygote { const Pickle& pickle, PickleIterator iter); - // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs - // fork() returns are not the real PIDs, so we need to map the Real PIDS - // into the sandbox PID namespace. - typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap; - ProcessMap real_pids_to_sandbox_pids; + // The Zygote needs to keep some information about each process. Most + // notably what the PID of the process is inside the PID namespace of + // the Zygote and whether or not a process was started by the + // ZygoteForkDelegate helper. + ZygoteProcessMap process_info_map_; const int sandbox_flags_; ZygoteForkDelegate* helper_; diff --git a/chromium/content/zygote/zygote_main_linux.cc b/chromium/content/zygote/zygote_main_linux.cc index 1f0e9f5fb52..567b3055ccc 100644 --- a/chromium/content/zygote/zygote_main_linux.cc +++ b/chromium/content/zygote/zygote_main_linux.cc @@ -16,10 +16,7 @@ #include "base/basictypes.h" #include "base/command_line.h" -#include "base/containers/hash_tables.h" -#include "base/files/file_path.h" #include "base/linux_util.h" -#include "base/memory/scoped_ptr.h" #include "base/native_library.h" #include "base/pickle.h" #include "base/posix/eintr_wrapper.h" @@ -27,6 +24,7 @@ #include "base/rand_util.h" #include "base/sys_info.h" #include "build/build_config.h" +#include "content/common/child_process_sandbox_support_impl_linux.h" #include "content/common/font_config_ipc_linux.h" #include "content/common/pepper_plugin_list.h" #include "content/common/sandbox_linux.h" @@ -69,7 +67,7 @@ static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, uint8_t reply_buf[512]; const ssize_t r = UnixDomainSocket::SendRecvMsg( - Zygote::kMagicSandboxIPCDescriptor, reply_buf, sizeof(reply_buf), NULL, + GetSandboxFD(), reply_buf, sizeof(reply_buf), NULL, request); if (r == -1) { memset(output, 0, sizeof(struct tm)); @@ -304,6 +302,8 @@ static void PreSandboxInit() { #if defined(ENABLE_WEBRTC) InitializeWebRtcModule(); #endif + SkFontConfigInterface::SetGlobal( + new FontConfigIPC(GetSandboxFD()))->unref(); } // Do nothing here @@ -384,16 +384,22 @@ static bool CreateInitProcessReaper() { // This will set the *using_suid_sandbox variable to true if the SUID sandbox // is enabled. This does not necessarily exclude other types of sandboxing. -static bool EnterSandbox(sandbox::SetuidSandboxClient* setuid_sandbox, - bool* using_suid_sandbox, bool* has_started_new_init) { +static bool EnterSuidSandbox(LinuxSandbox* linux_sandbox, + bool* using_suid_sandbox, + bool* has_started_new_init) { *using_suid_sandbox = false; *has_started_new_init = false; + + sandbox::SetuidSandboxClient* setuid_sandbox = + linux_sandbox->setuid_sandbox_client(); + if (!setuid_sandbox) return false; PreSandboxInit(); - SkFontConfigInterface::SetGlobal( - new FontConfigIPC(Zygote::kMagicSandboxIPCDescriptor))->unref(); + + // Check that the pre-sandbox initialization didn't spawn threads. + DCHECK(linux_sandbox->IsSingleThreaded()); if (setuid_sandbox->IsSuidSandboxChild()) { // Use the SUID sandbox. This still allows the seccomp sandbox to @@ -461,12 +467,9 @@ bool ZygoteMain(const MainFunctionParams& params, // This will pre-initialize the various sandboxes that need it. linux_sandbox->PreinitializeSandbox(); - sandbox::SetuidSandboxClient* setuid_sandbox = - linux_sandbox->setuid_sandbox_client(); - if (forkdelegate != NULL) { VLOG(1) << "ZygoteMain: initializing fork delegate"; - forkdelegate->Init(Zygote::kMagicSandboxIPCDescriptor); + forkdelegate->Init(GetSandboxFD()); } else { VLOG(1) << "ZygoteMain: fork delegate is NULL"; } @@ -475,14 +478,17 @@ bool ZygoteMain(const MainFunctionParams& params, bool using_suid_sandbox = false; bool has_started_new_init = false; - if (!EnterSandbox(setuid_sandbox, - &using_suid_sandbox, - &has_started_new_init)) { + if (!EnterSuidSandbox(linux_sandbox, + &using_suid_sandbox, + &has_started_new_init)) { LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: " << errno << ")"; return false; } + sandbox::SetuidSandboxClient* setuid_sandbox = + linux_sandbox->setuid_sandbox_client(); + if (setuid_sandbox->IsInNewPIDNamespace() && !has_started_new_init) { LOG(ERROR) << "The SUID sandbox created a new PID namespace but Zygote " "is not the init process. Please, make sure the SUID " |