summaryrefslogtreecommitdiff
path: root/chromium/content/zygote
diff options
context:
space:
mode:
authorAndras Becsi <andras.becsi@digia.com>2013-12-11 21:33:03 +0100
committerAndras Becsi <andras.becsi@digia.com>2013-12-13 12:34:07 +0100
commitf2a33ff9cbc6d19943f1c7fbddd1f23d23975577 (patch)
tree0586a32aa390ade8557dfd6b4897f43a07449578 /chromium/content/zygote
parent5362912cdb5eea702b68ebe23702468d17c3017a (diff)
downloadqtwebengine-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.cc136
-rw-r--r--chromium/content/zygote/zygote_linux.h40
-rw-r--r--chromium/content/zygote/zygote_main_linux.cc36
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 "