diff options
-rw-r--r-- | chrome/app/chrome_main.cc | 11 | ||||
-rw-r--r-- | content/browser/child_process_launcher.cc | 6 | ||||
-rw-r--r-- | content/browser/zygote_host_linux.cc | 10 | ||||
-rw-r--r-- | content/browser/zygote_host_linux.h | 10 | ||||
-rw-r--r-- | content/browser/zygote_main_linux.cc | 113 | ||||
-rw-r--r-- | content/common/content_switches.cc | 4 | ||||
-rw-r--r-- | content/common/content_switches.h | 4 | ||||
-rw-r--r-- | content/common/sandbox_methods_linux.h | 4 | ||||
-rw-r--r-- | content/common/zygote_fork_delegate_linux.h | 49 |
9 files changed, 161 insertions, 50 deletions
diff --git a/chrome/app/chrome_main.cc b/chrome/app/chrome_main.cc index c45916c8..3b45594 100644 --- a/chrome/app/chrome_main.cc +++ b/chrome/app/chrome_main.cc @@ -76,6 +76,10 @@ #include <signal.h> #endif +#if defined(OS_POSIX) && !defined(OS_MACOSX) +#include "content/common/zygote_fork_delegate_linux.h" +#endif + #if defined(OS_CHROMEOS) #include "base/sys_info.h" #include "chrome/browser/chromeos/boot_times_loader.h" @@ -114,7 +118,10 @@ extern int WorkerMain(const MainFunctionParams&); extern int NaClMain(const MainFunctionParams&); extern int UtilityMain(const MainFunctionParams&); extern int ProfileImportMain(const MainFunctionParams&); -extern int ZygoteMain(const MainFunctionParams&); +#if defined(OS_POSIX) && !defined(OS_MACOSX) +extern int ZygoteMain(const MainFunctionParams&, + ZygoteForkDelegate* forkdelegate); +#endif #if defined(_WIN64) extern int NaClBrokerMain(const MainFunctionParams&); #endif @@ -452,7 +459,7 @@ int RunZygote(const MainFunctionParams& main_function_params) { media::InitializeMediaLibrary(media_path); // This function call can return multiple times, once per fork(). - if (!ZygoteMain(main_function_params)) + if (!ZygoteMain(main_function_params, NULL)) return 1; // Zygote::HandleForkRequest may have reallocated the command diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index 7bb603f..7bada19 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc @@ -127,8 +127,9 @@ class ChildProcessLauncher::Context mapping.push_back(std::pair<uint32_t, int>(kCrashDumpSignal, crash_signal_fd)); } - handle = ZygoteHost::GetInstance()->ForkRenderer(cmd_line->argv(), - mapping); + handle = ZygoteHost::GetInstance()->ForkRequest(cmd_line->argv(), + mapping, + process_type); } else // Fall through to the normal posix case below when we're not zygoting. #endif @@ -378,4 +379,3 @@ void ChildProcessLauncher::SetTerminateChildOnShutdown( if (context_) context_->set_terminate_child_on_shutdown(terminate_on_shutdown); } - diff --git a/content/browser/zygote_host_linux.cc b/content/browser/zygote_host_linux.cc index 955628d..fc9a520 100644 --- a/content/browser/zygote_host_linux.cc +++ b/content/browser/zygote_host_linux.cc @@ -58,8 +58,7 @@ ZygoteHost::ZygoteHost() init_(false), using_suid_sandbox_(false), have_read_sandbox_status_word_(false), - sandbox_status_(0) { -} + sandbox_status_(0) {} ZygoteHost::~ZygoteHost() { if (init_) @@ -110,6 +109,7 @@ void ZygoteHost::Init(const std::string& sandbox_cmd) { switches::kRegisterPepperPlugins, switches::kDisableSeccompSandbox, switches::kEnableSeccompSandbox, + switches::kNaClLinuxHelper, }; cmd_line.CopySwitchesFrom(browser_command_line, kForwardSwitches, arraysize(kForwardSwitches)); @@ -223,13 +223,15 @@ ssize_t ZygoteHost::ReadReply(void* buf, size_t buf_len) { return HANDLE_EINTR(read(control_fd_, buf, buf_len)); } -pid_t ZygoteHost::ForkRenderer( +pid_t ZygoteHost::ForkRequest( const std::vector<std::string>& argv, - const base::GlobalDescriptors::Mapping& mapping) { + const base::GlobalDescriptors::Mapping& mapping, + const std::string& process_type) { DCHECK(init_); Pickle pickle; pickle.WriteInt(kCmdFork); + pickle.WriteString(process_type); pickle.WriteInt(argv.size()); for (std::vector<std::string>::const_iterator i = argv.begin(); i != argv.end(); ++i) diff --git a/content/browser/zygote_host_linux.h b/content/browser/zygote_host_linux.h index 5ead5f5..9098e6d 100644 --- a/content/browser/zygote_host_linux.h +++ b/content/browser/zygote_host_linux.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -32,10 +32,12 @@ class ZygoteHost { void Init(const std::string& sandbox_cmd); - // Tries to start a renderer process. Returns its pid on success, otherwise + // Tries to start a process of type indicated by process_type. + // Returns its pid on success, otherwise // base::kNullProcessHandle; - pid_t ForkRenderer(const std::vector<std::string>& command_line, - const base::GlobalDescriptors::Mapping& mapping); + pid_t ForkRequest(const std::vector<std::string>& command_line, + const base::GlobalDescriptors::Mapping& mapping, + const std::string& process_type); void EnsureProcessTerminated(pid_t process); // Get the termination status (and, optionally, the exit code) of diff --git a/content/browser/zygote_main_linux.cc b/content/browser/zygote_main_linux.cc index 99a7735..95b3975 100644 --- a/content/browser/zygote_main_linux.cc +++ b/content/browser/zygote_main_linux.cc @@ -37,9 +37,11 @@ #include "content/common/sandbox_methods_linux.h" #include "content/common/set_process_title.h" #include "content/common/unix_domain_socket_posix.h" +#include "content/common/zygote_fork_delegate_linux.h" #include "seccompsandbox/sandbox.h" #include "skia/ext/SkFontHost_fontconfig_control.h" #include "unicode/timezone.h" +#include "ipc/ipc_switches.h" #if defined(OS_LINUX) #include <sys/epoll.h> @@ -97,8 +99,9 @@ static void SELinuxTransitionToTypeOrDie(const char* type) { // runs it. class Zygote { public: - explicit Zygote(int sandbox_flags) - : sandbox_flags_(sandbox_flags) { + explicit Zygote(int sandbox_flags, ZygoteForkDelegate* helper) + : sandbox_flags_(sandbox_flags), + helper_(helper) { } bool ProcessRequests() { @@ -165,6 +168,7 @@ class Zygote { case ZygoteHost::kCmdFork: // This function call can return multiple times, once per fork(). return HandleForkRequest(fd, pickle, iter, fds); + case ZygoteHost::kCmdReap: if (!fds.empty()) break; @@ -247,9 +251,12 @@ class Zygote { // sandbox, it returns the real PID of the child process as it // appears outside the sandbox, rather than returning the PID inside // the sandbox. - int ForkWithRealPid() { - if (!g_suid_sandbox_active) + int ForkWithRealPid(const std::string& process_type, std::vector<int>& fds, + const std::string& channel_switch) { + const bool use_helper = (helper_ && helper_->CanHelp(process_type)); + if (!(use_helper || g_suid_sandbox_active)) { return fork(); + } int dummy_fd; ino_t dummy_inode; @@ -270,7 +277,13 @@ class Zygote { goto error; } - pid = fork(); + if (use_helper) { + fds.push_back(dummy_fd); + fds.push_back(pipe_fds[0]); + pid = helper_->Fork(fds); + } else { + pid = fork(); + } if (pid < 0) { goto error; } else if (pid == 0) { @@ -294,33 +307,43 @@ class Zygote { dummy_fd = -1; close(pipe_fds[0]); pipe_fds[0] = -1; - uint8_t reply_buf[512]; - Pickle request; - request.WriteInt(LinuxSandbox::METHOD_GET_CHILD_WITH_INODE); - request.WriteUInt64(dummy_inode); - - const ssize_t r = UnixDomainSocket::SendRecvMsg( - kMagicSandboxIPCDescriptor, reply_buf, sizeof(reply_buf), NULL, - request); - if (r == -1) { - LOG(ERROR) << "Failed to get child process's real PID"; - goto error; - } - base::ProcessId real_pid; - Pickle reply(reinterpret_cast<char*>(reply_buf), r); - void* iter2 = NULL; - if (!reply.ReadInt(&iter2, &real_pid)) - goto error; - if (real_pid <= 0) { - // METHOD_GET_CHILD_WITH_INODE failed. Did the child die already? - LOG(ERROR) << "METHOD_GET_CHILD_WITH_INODE failed"; - goto error; + if (g_suid_sandbox_active) { + uint8_t reply_buf[512]; + Pickle request; + request.WriteInt(LinuxSandbox::METHOD_GET_CHILD_WITH_INODE); + request.WriteUInt64(dummy_inode); + + const ssize_t r = UnixDomainSocket::SendRecvMsg( + kMagicSandboxIPCDescriptor, reply_buf, sizeof(reply_buf), NULL, + request); + if (r == -1) { + LOG(ERROR) << "Failed to get child process's real PID"; + goto error; + } + + Pickle reply(reinterpret_cast<char*>(reply_buf), r); + void* iter = NULL; + if (!reply.ReadInt(&iter, &real_pid)) + goto error; + if (real_pid <= 0) { + // METHOD_GET_CHILD_WITH_INODE failed. Did the child die already? + LOG(ERROR) << "METHOD_GET_CHILD_WITH_INODE failed"; + goto error; + } + real_pids_to_sandbox_pids[real_pid] = pid; } - real_pids_to_sandbox_pids[real_pid] = pid; - if (HANDLE_EINTR(write(pipe_fds[1], "x", 1)) != 1) { - LOG(ERROR) << "Failed to synchronise with child process"; - goto error; + 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; + } + } else { + if (HANDLE_EINTR(write(pipe_fds[1], "x", 1)) != 1) { + LOG(ERROR) << "Failed to synchronise with child process"; + goto error; + } } close(pipe_fds[1]); return real_pid; @@ -342,12 +365,19 @@ class Zygote { // Handle a 'fork' request from the browser: this means that the browser // wishes to start a new renderer. - bool HandleForkRequest(int fd, const Pickle& pickle, void* iter, - std::vector<int>& fds) { + bool HandleForkRequest(int fd, const Pickle& pickle, + void* iter, std::vector<int>& fds) { std::vector<std::string> args; int argc, numfds; base::GlobalDescriptors::Mapping mapping; base::ProcessId child; + std::string process_type; + std::string channel_id; + const std::string channel_id_prefix = std::string("--") + + switches::kProcessChannelID + std::string("="); + + if (!pickle.ReadString(&iter, &process_type)) + goto error; if (!pickle.ReadInt(&iter, &argc)) goto error; @@ -357,6 +387,8 @@ class Zygote { if (!pickle.ReadString(&iter, &arg)) goto error; args.push_back(arg); + if (arg.compare(0, channel_id_prefix.length(), channel_id_prefix) == 0) + channel_id = arg; } if (!pickle.ReadInt(&iter, &numfds)) @@ -374,7 +406,7 @@ class Zygote { mapping.push_back(std::make_pair( static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor)); - child = ForkWithRealPid(); + child = ForkWithRealPid(process_type, fds, channel_id); if (!child) { #if defined(SECCOMP_SANDBOX) @@ -447,6 +479,7 @@ class Zygote { ProcessMap real_pids_to_sandbox_pids; const int sandbox_flags_; + ZygoteForkDelegate* helper_; }; // With SELinux we can carve out a precise sandbox, so we don't have to play @@ -705,7 +738,8 @@ static bool EnterSandbox() { #endif // CHROMIUM_SELINUX -bool ZygoteMain(const MainFunctionParams& params) { +bool ZygoteMain(const MainFunctionParams& params, + ZygoteForkDelegate* forkdelegate) { #if !defined(CHROMIUM_SELINUX) g_am_zygote_or_renderer = true; #endif @@ -724,6 +758,15 @@ bool ZygoteMain(const MainFunctionParams& params) { } #endif // SECCOMP_SANDBOX + if (forkdelegate != NULL) { + VLOG(1) << "ZygoteMain: initializing fork delegate"; + forkdelegate->Init(getenv("SBX_D") != NULL, // g_suid_sandbox_active, + kBrowserDescriptor, + kMagicSandboxIPCDescriptor); + } else { + VLOG(1) << "ZygoteMain: fork delegate is NULL"; + } + // Turn on the SELinux or SUID sandbox if (!EnterSandbox()) { LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: " @@ -760,7 +803,7 @@ bool ZygoteMain(const MainFunctionParams& params) { } #endif // SECCOMP_SANDBOX - Zygote zygote(sandbox_flags); + Zygote zygote(sandbox_flags, forkdelegate); // This function call can return multiple times, once per fork(). return zygote.ProcessRequests(); } diff --git a/content/common/content_switches.cc b/content/common/content_switches.cc index ba2448f..e18ccbf 100644 --- a/content/common/content_switches.cc +++ b/content/common/content_switches.cc @@ -275,6 +275,10 @@ const char kLowLatencyAudio[] = "enable-low-latency-audio"; // (used for launching NaCl loader processes on 64-bit Windows). const char kNaClBrokerProcess[] = "nacl-broker"; +// Enables experimental lightweight Native Client launcher for Linux +// Value is the path to the helper binary. +const char kNaClLinuxHelper[] = "nacl-linux-helper"; + // Causes the process to run as a NativeClient loader. const char kNaClLoaderProcess[] = "nacl-loader"; diff --git a/content/common/content_switches.h b/content/common/content_switches.h index 868ad84..c94af06 100644 --- a/content/common/content_switches.h +++ b/content/common/content_switches.h @@ -92,6 +92,10 @@ extern const char kLowLatencyAudio[]; // TODO(jam): this doesn't belong in content. extern const char kNaClBrokerProcess[]; extern const char kNaClLoaderProcess[]; +// TODO(bradchen): remove kNaClLinuxHelper switch. +// This switch enables the experimental lightweight nacl_helper for Linux. +// It will be going away soon, when the helper is enabled permanently. +extern const char kNaClLinuxHelper[]; extern const char kNoDisplayingInsecureContent[]; extern const char kNoJsRandomness[]; extern const char kNoReferrers[]; diff --git a/content/common/sandbox_methods_linux.h b/content/common/sandbox_methods_linux.h index 02287f6d..f048ad8 100644 --- a/content/common/sandbox_methods_linux.h +++ b/content/common/sandbox_methods_linux.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,7 +7,7 @@ #pragma once // This is a list of sandbox IPC methods which the renderer may send to the -// sandbox host. See http://code.google.com/p/chromium/LinuxSandboxIPC +// sandbox host. See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC // This isn't the full list, values < 32 are reserved for methods called from // Skia. class LinuxSandbox { diff --git a/content/common/zygote_fork_delegate_linux.h b/content/common/zygote_fork_delegate_linux.h new file mode 100644 index 0000000..26dfbc9 --- /dev/null +++ b/content/common/zygote_fork_delegate_linux.h @@ -0,0 +1,49 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_COMMON_ZYGOTE_FORK_DELEGATE_LINUX_H_ +#define CONTENT_COMMON_ZYGOTE_FORK_DELEGATE_LINUX_H_ +#pragma once + +#include <unistd.h> + +#include <string> +#include <vector> + +#include "base/basictypes.h" + +// The ZygoteForkDelegate allows the Chrome Linux zygote to delegate +// fork operations to another class that knows how to do some +// specialized version of fork. +class ZygoteForkDelegate { + public: + // A ZygoteForkDelegate is created during Chrome linux zygote + // initialization, and provides "fork()" functionality with + // as an alternative to forking the zygote. A new delegate is + // passed in as an argument to ZygoteMain(). + ZygoteForkDelegate() {} + virtual ~ZygoteForkDelegate() {} + + // Initialization happens in the zygote after it has been + // started by ZygoteMain. + virtual void Init(bool sandboxed, + int browserdesc, + int sandboxdesc) = 0; + + // Returns 'true' if the delegate would like to handle a given + // fork request. Otherwise returns false. + virtual bool CanHelp(const std::string& process_type) = 0; + + // Delegate forks, returning a -1 on failure. Outside the + // suid sandbox, Fork() returns the Linux process ID. Inside + // the sandbox, returns a positive integer, with PID discovery + // handled by the sandbox. + virtual pid_t Fork(const std::vector<int>& fds) = 0; + + // After a successful for, signal the child to indicate that + // the child's PID has been received. Also communicate the + // channel switch as a part of acknowledgement message. + virtual bool AckChild(int fd, const std::string& channel_switch) = 0; +}; +#endif // CONTENT_COMMON_ZYGOTE_FORK_DELEGATE_LINUX_H_ |