summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/chrome_main.cc11
-rw-r--r--content/browser/child_process_launcher.cc6
-rw-r--r--content/browser/zygote_host_linux.cc10
-rw-r--r--content/browser/zygote_host_linux.h10
-rw-r--r--content/browser/zygote_main_linux.cc113
-rw-r--r--content/common/content_switches.cc4
-rw-r--r--content/common/content_switches.h4
-rw-r--r--content/common/sandbox_methods_linux.h4
-rw-r--r--content/common/zygote_fork_delegate_linux.h49
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_