summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/process_util.h9
-rw-r--r--base/process_util_posix.cc37
-rw-r--r--chrome/app/chrome_main.cc12
-rw-r--r--chrome/common/nacl_fork_delegate_linux.h37
-rw-r--r--chrome/common/nacl_helper_linux.h46
-rw-r--r--chrome/common/nacl_types.h6
-rw-r--r--chrome/nacl.gypi24
-rw-r--r--chrome/nacl/nacl_fork_delegate_linux.cc119
-rw-r--r--chrome/nacl/nacl_helper_linux.cc167
-rw-r--r--chrome/nacl/nacl_launcher_thread.h33
-rw-r--r--chrome/nacl/nacl_listener.cc (renamed from chrome/nacl/nacl_launcher_thread.cc)62
-rw-r--r--chrome/nacl/nacl_listener.h31
-rw-r--r--chrome/nacl/nacl_main.cc10
-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.cc108
-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
21 files changed, 662 insertions, 126 deletions
diff --git a/base/process_util.h b/base/process_util.h
index 3e758d4..9f66669 100644
--- a/base/process_util.h
+++ b/base/process_util.h
@@ -286,6 +286,15 @@ BASE_API bool LaunchAppInNewProcessGroup(
bool wait,
ProcessHandle* process_handle);
+#if defined(OS_LINUX)
+// Similar to LaunchApp variants above except uses clone(.. clone_flags ..)
+// rather than fork(). This is useful for work inside the setuid sandbox.
+BASE_API bool LaunchAppWithClone(const std::vector<std::string>& argv,
+ const file_handle_mapping_vector& fds_to_remap,
+ bool wait, ProcessHandle* process_handle,
+ int clone_flags);
+#endif
+
// AlterEnvironment returns a modified environment vector, constructed from the
// given environment and the list of changes given in |changes|. Each key in
// the environment is matched against the first element of the pairs. In the
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc
index a2398ed..1486128 100644
--- a/base/process_util_posix.cc
+++ b/base/process_util_posix.cc
@@ -508,15 +508,25 @@ bool LaunchAppImpl(
const file_handle_mapping_vector& fds_to_remap,
bool wait,
ProcessHandle* process_handle,
- bool start_new_process_group) {
- pid_t pid;
+ bool start_new_process_group,
+ bool use_clone,
+ int clone_flags) {
+ pid_t pid = -1;
InjectiveMultimap fd_shuffle1, fd_shuffle2;
fd_shuffle1.reserve(fds_to_remap.size());
fd_shuffle2.reserve(fds_to_remap.size());
scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
scoped_array<char*> new_environ(AlterEnvironment(env_changes, environ));
- pid = fork();
+ if (use_clone) {
+#if defined(OS_LINUX)
+ pid = syscall(__NR_clone, clone_flags, 0, 0, 0);
+#else
+ NOTREACHED() << "Tried to use clone() on non-Linux system.";
+#endif
+ } else {
+ pid = fork();
+ }
if (pid < 0) {
PLOG(ERROR) << "fork";
return false;
@@ -617,7 +627,10 @@ bool LaunchApp(
bool wait,
ProcessHandle* process_handle) {
return LaunchAppImpl(argv, env_changes, fds_to_remap,
- wait, process_handle, false);
+ wait, process_handle,
+ false, // don't start new process group
+ false, // don't use clone()
+ 0); // clone flags
}
bool LaunchAppInNewProcessGroup(
@@ -627,7 +640,21 @@ bool LaunchAppInNewProcessGroup(
bool wait,
ProcessHandle* process_handle) {
return LaunchAppImpl(argv, env_changes, fds_to_remap, wait,
- process_handle, true);
+ process_handle,
+ true, // start new process group
+ false, // don't use clone()
+ 0); // clone flags
+}
+
+BASE_API bool LaunchAppWithClone(const std::vector<std::string>& argv,
+ const file_handle_mapping_vector& fds_to_remap,
+ bool wait, ProcessHandle* process_handle,
+ int clone_flags) {
+ base::environment_vector no_env;
+ return LaunchAppImpl(argv, no_env, fds_to_remap, wait, process_handle,
+ false, // don't start new process group
+ true, // use clone()
+ clone_flags);
}
bool LaunchApp(const std::vector<std::string>& argv,
diff --git a/chrome/app/chrome_main.cc b/chrome/app/chrome_main.cc
index ed3827b..5130195 100644
--- a/chrome/app/chrome_main.cc
+++ b/chrome/app/chrome_main.cc
@@ -47,6 +47,11 @@
#include "ui/base/ui_base_paths.h"
#include "ui/base/ui_base_switches.h"
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#include "chrome/common/nacl_fork_delegate_linux.h"
+#include "content/common/zygote_fork_delegate_linux.h"
+#endif
+
#if defined(OS_WIN)
#include <algorithm>
#include <malloc.h>
@@ -112,7 +117,9 @@ 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&, const ZygoteForkDelegate&);
+#endif
#if defined(_WIN64)
extern int NaClBrokerMain(const MainFunctionParams&);
#endif
@@ -450,7 +457,8 @@ 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))
+ NaClForkDelegate nacl_fork_delegate;
+ if (!ZygoteMain(main_function_params, nacl_fork_delegate))
return 1;
// Zygote::HandleForkRequest may have reallocated the command
diff --git a/chrome/common/nacl_fork_delegate_linux.h b/chrome/common/nacl_fork_delegate_linux.h
new file mode 100644
index 0000000..e84961e
--- /dev/null
+++ b/chrome/common/nacl_fork_delegate_linux.h
@@ -0,0 +1,37 @@
+// 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 CHROME_COMMON_NACL_FORK_DELEGATE_LINUX_H_
+#define CHROME_COMMON_NACL_FORK_DELEGATE_LINUX_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "content/common/zygote_fork_delegate_linux.h"
+
+// The NaClForkDelegate is created during Chrome linux zygote
+// initialization, and provides "fork()" functionality with
+// NaCl specific process characteristics (specifically address
+// space layout) as an alternative to forking the zygote.
+// A new delegate is passed in as an argument to ZygoteMain().
+class NaClForkDelegate : public ZygoteForkDelegate {
+ public:
+ NaClForkDelegate();
+ virtual ~NaClForkDelegate();
+
+ virtual void Init(bool sandboxed,
+ int browserdesc,
+ int sandboxdesc) OVERRIDE;
+ virtual bool CanHelp(const std::string& process_type) OVERRIDE;
+ virtual pid_t Fork(const std::vector<int>& fds) OVERRIDE;
+ virtual bool AckChild(int fd,
+ const std::string& channel_switch) OVERRIDE;
+
+ private:
+ bool sandboxed_;
+ int fd_;
+ pid_t pid_;
+};
+
+#endif // CHROME_COMMON_NACL_FORK_DELEGATE_LINUX_H_
diff --git a/chrome/common/nacl_helper_linux.h b/chrome/common/nacl_helper_linux.h
new file mode 100644
index 0000000..a7e916d
--- /dev/null
+++ b/chrome/common/nacl_helper_linux.h
@@ -0,0 +1,46 @@
+// 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 CHROME_COMMON_NACL_HELPER_LINUX_H_
+#define CHROME_COMMON_NACL_HELPER_LINUX_H_
+#pragma once
+
+// A mini-zygote specifically for Native Client. This file defines
+// constants used to implement communication between the nacl_helper
+// process and the Chrome zygote.
+
+// Used by Helper to tell Zygote it has started successfully.
+#define kNaClHelperStartupAck "NACLHELPER_OK"
+// Used by Zygote to ask Helper to fork a new NaCl loader.
+#define kNaClForkRequest "NACLFORK"
+
+// The next set of constants define global Linux file descriptors.
+// For communications between NaCl loader and browser.
+// See also content/common/zygote_main_linux.cc and
+// http://code.google.com/p/chromium/wiki/LinuxZygote
+#define kNaClBrowserDescriptor 3
+// For communications between NaCl loader and zygote.
+// We put the kNaClZygoteDescriptor on 3 together with the
+// kNaClBrowserDescriptor. They are never used at the same
+// time, and this prevents /dev/urandom from using the fd.
+#define kNaClZygoteDescriptor 3
+// For communications between the NaCl loader process and
+// the SUID sandbox.
+#define kNaClSandboxDescriptor 5
+// NOTE: kNaClBrowserDescriptor and kNaClSandboxDescriptor must match
+// content/browser/zygote_main_linux.cc kBrowserDescriptor and
+// kMagicSandboxIPCDescriptor.
+
+// A fork request from the Zygote to the helper includes an array
+// of three file descriptors. These constants are used as indicies
+// into the array.
+// Used to pass in the descriptor for talking to the Browser
+#define kNaClBrowserFDIndex 0
+// The next two are used in the protocol for discovering the
+// child processes real PID from within the SUID sandbox. See
+// http://code.google.com/p/chromium/wiki/LinuxZygote
+#define kNaClDummyFDIndex 1
+#define kNaClParentFDIndex 2
+
+#endif // CHROME_COMMON_NACL_HELPER_LINUX_H_
diff --git a/chrome/common/nacl_types.h b/chrome/common/nacl_types.h
index b61d9ef..bcc1005 100644
--- a/chrome/common/nacl_types.h
+++ b/chrome/common/nacl_types.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,6 +7,7 @@
#define CHROME_COMMON_NACL_TYPES_H_
#pragma once
+#include "base/native_library.h" // for HANDLE and OS_POSIX
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
#endif
@@ -19,7 +20,8 @@ namespace nacl {
inline HANDLE ToNativeHandle(const FileDescriptor& desc) {
return reinterpret_cast<HANDLE>(desc);
}
-#elif defined(OS_POSIX)
+#endif
+#if defined(OS_POSIX)
typedef base::FileDescriptor FileDescriptor;
inline int ToNativeHandle(const FileDescriptor& desc) {
return desc.fd;
diff --git a/chrome/nacl.gypi b/chrome/nacl.gypi
index 9b7e6b4..21fbb01 100644
--- a/chrome/nacl.gypi
+++ b/chrome/nacl.gypi
@@ -28,8 +28,8 @@
'nacl/nacl_main_platform_delegate_linux.cc',
'nacl/nacl_main_platform_delegate_mac.mm',
'nacl/nacl_main_platform_delegate_win.cc',
- 'nacl/nacl_launcher_thread.cc',
- 'nacl/nacl_launcher_thread.h',
+ 'nacl/nacl_listener.cc',
+ 'nacl/nacl_listener.h',
],
# TODO(gregoryd): consider switching NaCl to use Chrome OS defines
'conditions': [
@@ -45,6 +45,9 @@
'defines': [
'__STDC_LIMIT_MACROS=1',
],
+ 'sources': [
+ 'nacl/nacl_fork_delegate_linux.cc',
+ ],
},],
],
}],
@@ -141,5 +144,22 @@
},
],
}],
+ ['OS=="linux"', {
+ 'targets': [
+ {
+ 'target_name': 'nacl_helper',
+ 'type': 'executable',
+ 'include_dirs': [
+ '..',
+ ],
+ 'dependencies': [
+ 'nacl',
+ ],
+ 'sources': [
+ '../chrome/nacl/nacl_helper_linux.cc',
+ ],
+ },
+ ],
+ }],
],
}
diff --git a/chrome/nacl/nacl_fork_delegate_linux.cc b/chrome/nacl/nacl_fork_delegate_linux.cc
new file mode 100644
index 0000000..edc5c08
--- /dev/null
+++ b/chrome/nacl/nacl_fork_delegate_linux.cc
@@ -0,0 +1,119 @@
+// 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.
+
+#include "chrome/common/nacl_fork_delegate_linux.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/file_path.h"
+#include "base/process_util.h"
+#include "content/common/unix_domain_socket_posix.h"
+#include "content/common/zygote_fork_delegate_linux.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/nacl_helper_linux.h"
+
+NaClForkDelegate::NaClForkDelegate() : sandboxed_(false),
+ fd_(-1),
+ pid_(-1) {
+}
+
+void NaClForkDelegate::Init(const bool sandboxed,
+ const int browserdesc,
+ const int sandboxdesc) {
+ VLOG(1) << "NaClForkDelegate::Init()";
+ int fds[2];
+
+ sandboxed_ = sandboxed;
+ // Confirm a couple hard-wired assumptions.
+ // The NaCl constants are from chrome/nacl/nacl_linux_helper.h
+ DCHECK(kNaClBrowserDescriptor == browserdesc);
+ DCHECK(kNaClSandboxDescriptor == sandboxdesc);
+
+ CHECK(socketpair(PF_UNIX, SOCK_SEQPACKET, 0, fds) == 0);
+ base::file_handle_mapping_vector fds_to_map;
+ fds_to_map.push_back(std::make_pair(fds[1], kNaClZygoteDescriptor));
+ fds_to_map.push_back(std::make_pair(sandboxdesc, kNaClSandboxDescriptor));
+ // TODO(bradchen): Before making this the default for release builds,
+ // replace command line switch with PathService::Get().
+ const std::string nacl_zygote_exe =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kNaClLinuxHelper);
+ pid_ = -1;
+ if (nacl_zygote_exe.length() != 0) {
+ CommandLine::StringVector argv = CommandLine::ForCurrentProcess()->argv();
+ argv[0] = nacl_zygote_exe;
+ base::LaunchAppWithClone(argv, fds_to_map, false, &pid_,
+ CLONE_FS | SIGCHLD);
+ // parent and error cases are handled below
+ }
+ if (HANDLE_EINTR(close(fds[1])) < 0)
+ LOG(ERROR) << "close failed: " << errno;
+
+ if (pid_ > 0) {
+ const ssize_t kExpectedLength = strlen(kNaClHelperStartupAck);
+ char buf[kExpectedLength];
+
+ // Wait for ack from nacl_helper, indicating it is ready to help
+ const ssize_t nread = read(fds[0], buf, sizeof(buf));
+ if (nread == kExpectedLength &&
+ memcmp(buf, kNaClHelperStartupAck, nread) == 0) {
+ // all is well
+ fd_ = fds[0];
+ return;
+ }
+ LOG(ERROR) << "Bad NaCl helper startup ack (" << nread << " bytes)";
+ }
+ // TODO(bradchen): Make this LOG(ERROR) when the NaCl helper
+ // becomes the default.
+ pid_ = -1;
+ fd_ = -1;
+ if (HANDLE_EINTR(close(fds[0])) < 0)
+ LOG(ERROR) << "close failed: " << errno;
+}
+
+NaClForkDelegate::~NaClForkDelegate() {
+ // side effect of close: delegate process will terminate
+ if (HANDLE_EINTR(close(fd_)) < 0)
+ LOG(ERROR) << "close failed: " << errno;
+}
+
+bool NaClForkDelegate::CanHelp(const std::string& process_type) {
+ return (process_type == switches::kNaClLoaderProcess && pid_ != -1);
+}
+
+pid_t NaClForkDelegate::Fork(const std::vector<int>& fds) {
+ base::ProcessId naclchild;
+ VLOG(1) << "NaClForkDelegate::Fork";
+
+ DCHECK(fds.size() == kNaClParentFDIndex + 1);
+ if (!UnixDomainSocket::SendMsg(fd_, kNaClForkRequest,
+ strlen(kNaClForkRequest), fds)) {
+ LOG(ERROR) << "NaClForkDelegate::Fork: SendMsg failed";
+ return -1;
+ }
+ int nread = read(fd_, &naclchild, sizeof(naclchild));
+ if (nread != sizeof(naclchild)) {
+ LOG(ERROR) << "NaClForkDelegate::Fork: read failed";
+ return -1;
+ }
+ VLOG(1) << "nacl_child is " << naclchild << " (" << nread << " bytes)";
+ return naclchild;
+}
+
+bool NaClForkDelegate::AckChild(const int fd,
+ const std::string& channel_switch) {
+ int nwritten = HANDLE_EINTR(write(fd, channel_switch.c_str(),
+ channel_switch.length()));
+ if (nwritten != static_cast<int>(channel_switch.length())) {
+ return false;
+ }
+ return true;
+}
diff --git a/chrome/nacl/nacl_helper_linux.cc b/chrome/nacl/nacl_helper_linux.cc
new file mode 100644
index 0000000..693f67f
--- /dev/null
+++ b/chrome/nacl/nacl_helper_linux.cc
@@ -0,0 +1,167 @@
+// 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.
+
+// A mini-zygote specifically for Native Client.
+
+#include "chrome/common/nacl_helper_linux.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <string>
+#include <vector>
+
+#include "base/at_exit.h"
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/rand_util.h"
+#include "chrome/nacl/nacl_listener.h"
+#include "content/common/main_function_params.h"
+#include "content/common/unix_domain_socket_posix.h"
+#include "ipc/ipc_switches.h"
+
+namespace {
+
+bool g_suid_sandbox_active;
+
+// The child must mimic the behavior of zygote_main_linux.cc on the child
+// side of the fork. See zygote_main_linux.cc:HandleForkRequest from
+// if (!child) {
+// Note: this code doesn't attempt to support SELINUX or the SECCOMP sandbox.
+void BecomeNaClLoader(const std::vector<int>& child_fds) {
+ VLOG(1) << "NaCl loader: setting up IPC descriptor";
+ if (HANDLE_EINTR(close(kNaClZygoteDescriptor)) < 0)
+ LOG(ERROR) << "close failed: " << errno;
+
+ // Set up browser descriptor as expected by Chrome on fd 3
+ // The zygote takes care of putting the sandbox IPC channel on fd 5
+ int zfd = dup2(child_fds[kNaClBrowserFDIndex], kNaClBrowserDescriptor);
+ if (zfd != kNaClBrowserDescriptor) {
+ LOG(ERROR) << "Could not initialize kNaClBrowserDescriptor";
+ _exit(-1);
+ }
+
+ MessageLoopForIO main_message_loop;
+ NaClListener *listener = new NaClListener();
+ listener->Listen();
+ _exit(0);
+}
+
+// Some of this code was lifted from
+// content/browser/zygote_main_linux.cc:ForkWithRealPid()
+void HandleForkRequest(const std::vector<int>& child_fds) {
+ VLOG(1) << "nacl_helper: forking";
+ pid_t childpid = fork();
+ if (childpid < 0) {
+ perror("fork");
+ LOG(ERROR) << "*** HandleForkRequest failed\n";
+ // fall through to parent case below
+ } else if (childpid == 0) { // In the child process.
+ bool validack = false;
+ const size_t kMaxReadSize = 1024;
+ char buffer[kMaxReadSize];
+ // Wait until the parent process has discovered our PID. We
+ // should not fork any child processes (which the seccomp
+ // sandbox does) until then, because that can interfere with the
+ // parent's discovery of our PID.
+ const int nread = HANDLE_EINTR(read(child_fds[kNaClParentFDIndex], buffer,
+ kMaxReadSize));
+ const std::string switch_prefix = std::string("--") +
+ switches::kProcessChannelID + std::string("=");
+ const size_t len = switch_prefix.length();
+
+ if (nread < 0) {
+ perror("read");
+ LOG(ERROR) << "read returned " << nread;
+ } else if (nread > static_cast<int>(len)) {
+ if (switch_prefix.compare(0, len, buffer, 0, len) == 0) {
+ VLOG(1) << "NaCl loader is synchronised with Chrome zygote";
+ CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kProcessChannelID,
+ std::string(&buffer[len], nread - len));
+ validack = true;
+ }
+ }
+ if (HANDLE_EINTR(close(child_fds[kNaClDummyFDIndex])))
+ LOG(ERROR) << "close failed: " << errno;
+ if (HANDLE_EINTR(close(child_fds[kNaClParentFDIndex])))
+ LOG(ERROR) << "close failed: " << errno;
+
+ if (validack) {
+ BecomeNaClLoader(child_fds);
+ } else {
+ LOG(ERROR) << "Failed to synch with zygote";
+ }
+ // NOTREACHED
+ return;
+ }
+ // I am the parent.
+ // First, close the dummy_fd so the sandbox won't find me when
+ // looking for the child's pid in /proc. Also close other fds.
+ for (size_t i = 0; i < child_fds.size(); i++) {
+ if (HANDLE_EINTR(close(child_fds[i])))
+ LOG(ERROR) << "close failed: " << errno;
+ }
+ VLOG(1) << "nacl_helper: childpid is " << childpid;
+ // Now tell childpid to the Chrome zygote.
+ if (HANDLE_EINTR(send(kNaClZygoteDescriptor,
+ &childpid, sizeof(childpid), MSG_EOR))
+ != sizeof(childpid)) {
+ LOG(ERROR) << "*** send() to zygote failed";
+ }
+}
+
+} // namespace
+
+int main(int argc, char *argv[]) {
+ CommandLine::Init(argc, argv);
+ base::AtExitManager exit_manager;
+ base::RandUint64(); // acquire /dev/urandom fd before sandbox is raised
+ std::vector<int> empty; // for SendMsg() calls
+
+ g_suid_sandbox_active = (NULL != getenv("SBX_D"));
+
+ // Send the zygote a message to let it know we are ready to help
+ if (!UnixDomainSocket::SendMsg(kNaClZygoteDescriptor,
+ kNaClHelperStartupAck,
+ sizeof(kNaClHelperStartupAck), empty)) {
+ LOG(ERROR) << "*** send() to zygote failed";
+ }
+
+ while (true) {
+ int badpid = -1;
+ std::vector<int> fds;
+ static const unsigned kMaxMessageLength = 2048;
+ char buf[kMaxMessageLength];
+ const ssize_t msglen = UnixDomainSocket::RecvMsg(kNaClZygoteDescriptor,
+ &buf, sizeof(buf), &fds);
+ if (msglen == 0 || (msglen == -1 && errno == ECONNRESET)) {
+ // EOF from the browser. Goodbye!
+ _exit(0);
+ }
+ if (msglen == sizeof(kNaClForkRequest) - 1 &&
+ memcmp(buf, kNaClForkRequest, msglen) == 0) {
+ if (kNaClParentFDIndex + 1 == fds.size()) {
+ HandleForkRequest(fds);
+ continue; // fork succeeded. Note: child does not return
+ } else {
+ LOG(ERROR) << "nacl_helper: unexpected number of fds, got "
+ << fds.size();
+ }
+ } else {
+ if (msglen != 0) {
+ LOG(ERROR) << "nacl_helper unrecognized request: %s";
+ _exit(-1);
+ }
+ }
+ // if fork fails, send PID=-1 to zygote
+ if (!UnixDomainSocket::SendMsg(kNaClZygoteDescriptor, &badpid,
+ sizeof(badpid), empty)) {
+ LOG(ERROR) << "*** send() to zygote failed";
+ }
+ }
+}
diff --git a/chrome/nacl/nacl_launcher_thread.h b/chrome/nacl/nacl_launcher_thread.h
deleted file mode 100644
index 4d709d6..0000000
--- a/chrome/nacl/nacl_launcher_thread.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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 CHROME_NACL_NACL_THREAD_H_
-#define CHROME_NACL_NACL_THREAD_H_
-#pragma once
-
-#include "base/native_library.h"
-#include "chrome/common/nacl_types.h"
-#include "content/common/child_thread.h"
-
-// The NaClLauncherThread class represents a background thread where
-// NaCl app gets started.
-class NaClLauncherThread : public ChildThread {
- public:
- explicit NaClLauncherThread(bool debug);
- virtual ~NaClLauncherThread();
- // Returns the one NaCl thread.
- static NaClLauncherThread* current();
-
- private:
- virtual bool OnControlMessageReceived(const IPC::Message& msg);
- void OnStartSelLdr(std::vector<nacl::FileDescriptor> handles,
- bool have_irt_file);
-
- int debug_enabled_;
-
- // TODO(gregoryd): do we need to override Cleanup as in PluginThread?
- DISALLOW_COPY_AND_ASSIGN(NaClLauncherThread);
-};
-
-#endif // CHROME_NACL_NACL_THREAD_H_
diff --git a/chrome/nacl/nacl_launcher_thread.cc b/chrome/nacl/nacl_listener.cc
index ad1c5e4..9652070 100644
--- a/chrome/nacl/nacl_launcher_thread.cc
+++ b/chrome/nacl/nacl_listener.cc
@@ -2,13 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/nacl/nacl_launcher_thread.h"
+#include "chrome/nacl/nacl_listener.h"
-#include <vector>
+#include <errno.h>
-#include "base/atomicops.h"
+#include "base/command_line.h"
+#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
#include "chrome/common/nacl_messages.h"
+#include "ipc/ipc_channel.h"
+#include "ipc/ipc_switches.h"
#include "native_client/src/shared/imc/nacl_imc.h"
#if defined(OS_LINUX)
@@ -20,6 +24,15 @@
#include <io.h>
#endif
+// This is ugly. We need an interface header file for the exported
+// sel_ldr interfaces.
+// TODO(gregoryd,sehr): Add an interface header.
+#if defined(OS_WIN)
+typedef HANDLE NaClHandle;
+#else
+typedef int NaClHandle;
+#endif // NaClHandle
+
#if defined(OS_MACOSX)
namespace {
@@ -56,43 +69,34 @@ int CreateMemoryObject(size_t size, bool executable) {
} // namespace
#endif // defined(OS_MACOSX)
-// This is ugly. We need an interface header file for the exported
-// sel_ldr interfaces.
-// TODO(gregoryd,sehr): Add an interface header.
-#if defined(OS_WIN)
-typedef HANDLE NaClHandle;
-#else
-typedef int NaClHandle;
-#endif // NaClHandle
-
-// This is currently necessary because we have a conflict between
-// NaCl's LOG_FATAL (from platform/nacl_log.h) and Chromium's
-// LOG_FATAL (from base/logging.h).
-extern "C" int NaClMainForChromium(int handle_count, const NaClHandle* handles,
+extern "C" int NaClMainForChromium(int handle_count,
+ const NaClHandle* handles,
int debug);
extern "C" void NaClSetIrtFileDesc(int fd);
-NaClLauncherThread::NaClLauncherThread(bool debug) {
- debug_enabled_ = debug ? 1 : 0;
-}
+NaClListener::NaClListener() {}
-NaClLauncherThread::~NaClLauncherThread() {
-}
+NaClListener::~NaClListener() {}
-NaClLauncherThread* NaClLauncherThread::current() {
- return static_cast<NaClLauncherThread*>(ChildThread::current());
+void NaClListener::Listen() {
+ std::string channel_name =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kProcessChannelID);
+ IPC::Channel channel(channel_name, IPC::Channel::MODE_CLIENT, this);
+ CHECK(channel.Connect());
+ MessageLoop::current()->Run();
}
-bool NaClLauncherThread::OnControlMessageReceived(const IPC::Message& msg) {
+bool NaClListener::OnMessageReceived(const IPC::Message& msg) {
bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(NaClLauncherThread, msg)
- IPC_MESSAGE_HANDLER(NaClProcessMsg_Start, OnStartSelLdr)
- IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_BEGIN_MESSAGE_MAP(NaClListener, msg)
+ IPC_MESSAGE_HANDLER(NaClProcessMsg_Start, OnStartSelLdr)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
-void NaClLauncherThread::OnStartSelLdr(
+void NaClListener::OnStartSelLdr(
std::vector<nacl::FileDescriptor> handles,
bool have_irt_file) {
#if defined(OS_LINUX)
@@ -127,5 +131,5 @@ void NaClLauncherThread::OnStartSelLdr(
array[i] = nacl::ToNativeHandle(handles[i]);
}
NaClMainForChromium(static_cast<int>(handles.size()), array.get(),
- debug_enabled_);
+ false /* debug */);
}
diff --git a/chrome/nacl/nacl_listener.h b/chrome/nacl/nacl_listener.h
new file mode 100644
index 0000000..c326c95
--- /dev/null
+++ b/chrome/nacl/nacl_listener.h
@@ -0,0 +1,31 @@
+// 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 CHROME_NACL_NACL_LISTENER_H_
+#define CHROME_NACL_NACL_LISTENER_H_
+#pragma once
+
+#include <vector>
+
+#include "chrome/common/nacl_types.h"
+#include "ipc/ipc_channel.h"
+
+// The NaClListener is an IPC channel listener that waits for a
+// request to start a NaCl module.
+class NaClListener : public IPC::Channel::Listener {
+ public:
+ NaClListener();
+ virtual ~NaClListener();
+ // Listen for a request to launch a NaCl module.
+ void Listen();
+
+ private:
+ void OnStartSelLdr(std::vector<nacl::FileDescriptor> handles,
+ bool have_irt_file);
+ virtual bool OnMessageReceived(const IPC::Message& msg);
+
+ DISALLOW_COPY_AND_ASSIGN(NaClListener);
+};
+
+#endif // CHROME_NACL_NACL_LISTENER_H_
diff --git a/chrome/nacl/nacl_main.cc b/chrome/nacl/nacl_main.cc
index 64adb2c..e1564e2 100644
--- a/chrome/nacl/nacl_main.cc
+++ b/chrome/nacl/nacl_main.cc
@@ -15,13 +15,15 @@
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/logging_chrome.h"
-#include "chrome/nacl/nacl_launcher_thread.h"
+#include "chrome/nacl/nacl_listener.h"
#include "chrome/nacl/nacl_main_platform_delegate.h"
#include "content/common/child_process.h"
+#include "content/common/child_process_info.h"
#include "content/common/hi_res_timer_manager.h"
#include "content/common/main_function_params.h"
#include "content/common/result_codes.h"
#include "content/common/sandbox_policy.h"
+#include "ipc/ipc_switches.h"
#if defined(OS_WIN)
#include "chrome/nacl/broker_thread.h"
@@ -117,10 +119,8 @@ int NaClMain(const MainFunctionParams& parameters) {
bool sandbox_test_result = platform.RunSandboxTests();
if (sandbox_test_result) {
- ChildProcess nacl_process;
- bool debug = parsed_command_line.HasSwitch(switches::kEnableNaClDebug);
- nacl_process.set_main_thread(new NaClLauncherThread(debug));
- MessageLoop::current()->Run();
+ NaClListener listener;
+ listener.Listen();
} else {
// This indirectly prevents the test-harness-success-cookie from being set,
// as a way of communicating test failure, because the nexe won't reply.
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc
index 8d0ac12..3ba9d8a 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
@@ -374,4 +375,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 328c603..16cc514 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));
@@ -221,13 +221,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..477ca90 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_.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 NaCl child process";
+ 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,
+ const ZygoteForkDelegate& forkdelegate) {
#if !defined(CHROMIUM_SELINUX)
g_am_zygote_or_renderer = true;
#endif
@@ -724,6 +758,10 @@ bool ZygoteMain(const MainFunctionParams& params) {
}
#endif // SECCOMP_SANDBOX
+ VLOG(1) << "initializing fork delegate";
+ forkdelegate.Init(getenv("SBX_D") != NULL, // g_suid_sandbox_active,
+ kBrowserDescriptor, kMagicSandboxIPCDescriptor);
+
// Turn on the SELinux or SUID sandbox
if (!EnterSandbox()) {
LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: "
@@ -760,7 +798,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 7033c7f..3e22610 100644
--- a/content/common/content_switches.cc
+++ b/content/common/content_switches.cc
@@ -274,6 +274,10 @@ const char kLogPluginMessages[] = "log-plugin-messages";
// (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 f48e69a..1b2384f 100644
--- a/content/common/content_switches.h
+++ b/content/common/content_switches.h
@@ -92,6 +92,10 @@ extern const char kLogPluginMessages[];
// 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_