| Index: content/browser/zygote_main_linux.cc
|
| diff --git a/content/browser/zygote_main_linux.cc b/content/browser/zygote_main_linux.cc
|
| index 99a773556ff960383693cdc3e3fe7a0d1ae05ce2..a3085d59e966f46f97c9e8e624451c951a957240 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 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,
|
| + 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();
|
| }
|
|
|