Chromium Code Reviews| Index: content/browser/zygote_main_linux.cc |
| diff --git a/content/browser/zygote_main_linux.cc b/content/browser/zygote_main_linux.cc |
| index ef9dd0be039ba4e78c3f8936ccdde8b1e0b32aa7..090ae548c2f289e0c82bbbe30bdac167674fdde3 100644 |
| --- a/content/browser/zygote_main_linux.cc |
| +++ b/content/browser/zygote_main_linux.cc |
| @@ -38,6 +38,7 @@ |
| #include "crypto/nss_util.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "chrome/common/chrome_switches.h" |
| +#include "chrome/common/nacl_helper_linux.h" |
| #include "content/common/chrome_descriptors.h" |
| #include "content/common/font_config_ipc_linux.h" |
| #include "content/common/main_function_params.h" |
| @@ -68,6 +69,8 @@ static bool g_suid_sandbox_active = false; |
| #if defined(SECCOMP_SANDBOX) |
| // |g_proc_fd| is used only by the seccomp sandbox. |
| static int g_proc_fd = -1; |
| +static int g_nacl_helper_fd = -1; |
| +static base::ProcessId g_naclpid = -1; |
| #endif |
| #if defined(CHROMIUM_SELINUX) |
| @@ -161,8 +164,10 @@ class Zygote { |
| if (pickle.ReadInt(&iter, &kind)) { |
| switch (kind) { |
| case ZygoteHost::kCmdFork: |
| + case ZygoteHost::kCmdNaClFork: |
| // This function call can return multiple times, once per fork(). |
| - return HandleForkRequest(fd, pickle, iter, fds); |
| + return HandleForkRequest(fd, pickle, iter, fds, |
| + kind == ZygoteHost::kCmdNaClFork); |
| case ZygoteHost::kCmdReap: |
| if (!fds.empty()) |
| break; |
| @@ -241,13 +246,47 @@ class Zygote { |
| PLOG(ERROR) << "write"; |
| } |
| + base::ProcessId ForkNaClLauncher(std::vector<int>& fds) { |
| + base::ProcessId naclchild; |
| + VLOG(1) << "ForkNaClLauncher"; |
| + |
| + if (g_suid_sandbox_active) { |
| + DCHECK(fds.size() == kNaClParentFDIndex + 1); |
| + } else { |
| + DCHECK(fds.size() == kNaClSandboxFDIndex + 1); |
| + } |
| + if (!UnixDomainSocket::SendMsg(g_nacl_helper_fd, kNaClForkRequest, |
| + sizeof(kNaClForkRequest), fds)) { |
| + perror("ForkNaClLauncher: send failed"); |
| + return -1; |
| + } |
| + if (read(g_nacl_helper_fd, &naclchild, sizeof(naclchild)) |
| + != sizeof(naclchild)) { |
| + perror("ForkNaClLauncher: read failed"); |
|
Mark Seaborn
2011/06/15 16:09:04
You're calling perror() even if read() didn't retu
Brad Chen
2011/06/15 18:47:47
Done.
|
| + return -1; |
|
Mark Seaborn
2011/06/15 16:09:04
If the read() fails, don't you need to abandon the
Brad Chen
2011/06/15 18:47:47
Let's talk face-to-face about what makes sense in
|
| + } |
| + VLOG(1) << "nacl_child is " << naclchild; |
| + return naclchild; |
| + } |
| + |
| // This is equivalent to fork(), except that, when using the SUID |
| // 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) |
| - return fork(); |
| + int ForkWithRealPid(const bool naclfork, std::vector<int>& fds) { |
| + // If we didn't start a nacl helper, don't use it to fork. |
| + // TODO(bradchen): remove this once nacl helper is debugged |
| + bool isnaclfork = naclfork && (g_naclpid != -1); |
| + |
| + if (!g_suid_sandbox_active) { |
| + VLOG(1) << "suid sandbox NOT active"; |
| + VLOG(1) << "fds.size() is " << fds.size(); |
| + if (isnaclfork) { |
| + return ForkNaClLauncher(fds); |
| + } else { |
| + return fork(); |
| + } |
| + } |
| int dummy_fd; |
| ino_t dummy_inode; |
| @@ -268,7 +307,13 @@ class Zygote { |
| goto error; |
| } |
| - pid = fork(); |
| + if (isnaclfork) { |
| + fds.push_back(dummy_fd); |
| + fds.push_back(pipe_fds[0]); |
| + pid = ForkNaClLauncher(fds); |
| + } else { |
| + pid = fork(); |
| + } |
| if (pid < 0) { |
| goto error; |
| } else if (pid == 0) { |
| @@ -341,7 +386,7 @@ 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) { |
| + std::vector<int>& fds, const bool isnaclfork) { |
| std::vector<std::string> args; |
| int argc, numfds; |
| base::GlobalDescriptors::Mapping mapping; |
| @@ -372,7 +417,10 @@ class Zygote { |
| mapping.push_back(std::make_pair( |
| static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor)); |
| - child = ForkWithRealPid(); |
| + if (isnaclfork) { |
| + fds.push_back(kMagicSandboxIPCDescriptor); |
| + } |
| + child = ForkWithRealPid(isnaclfork, fds); |
| if (!child) { |
| #if defined(SECCOMP_SANDBOX) |
| @@ -447,6 +495,50 @@ class Zygote { |
| const int sandbox_flags_; |
| }; |
| +static void LaunchNaClHelper() { |
| + VLOG(1) << "LaunchNaClHelper"; |
| + int fds[2]; |
| + |
| + // Confirm a couple hard-wired assumptions. |
| + // The NaCl constants are from chrome/nacl/nacl_linux_helper.h |
| + DCHECK(kNaClZygoteDescriptor == kBrowserDescriptor); |
| + DCHECK(kNaClSandboxDescriptor == kMagicSandboxIPCDescriptor); |
| + |
| + 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], 3)); |
| + |
| + const char* nacl_zygote_exe = getenv("NACL_NEW_ZYGOTE"); |
| + g_naclpid = -1; |
| + if (NULL != nacl_zygote_exe) { |
| + CommandLine::StringVector argv = CommandLine::ForCurrentProcess()->argv(); |
| + argv[0] = nacl_zygote_exe; |
| + base::LaunchAppWithClone(argv, fds_to_map, false, &g_naclpid, |
|
Mark Seaborn
2011/06/15 16:09:04
If this takes fds_to_map, and you're passing CLONE
Brad Chen
2011/06/15 18:47:47
This code works, which suggests I might not be mes
|
| + CLONE_FS | SIGCHLD); |
| + } |
| + close(fds[1]); |
| + if (g_naclpid > 0) { |
| + const int kExpectedLength = sizeof(kNaClHelperMagic); |
| + char buf[kExpectedLength]; |
| + |
| + VLOG(1) << "NaCl Launcher PID is " << g_naclpid; |
| + int nread = read(fds[0], buf, sizeof(buf)); |
|
Mark Seaborn
2011/06/15 16:09:04
Please add a comment saying why you are waiting fo
Brad Chen
2011/06/15 18:47:47
Done.
|
| + DCHECK(nread == kExpectedLength) << "Incorrect NaCl helper magic length"; |
| + DCHECK(0 == strcmp(buf, kNaClHelperMagic)) << "Incorrect nacl helper magic"; |
|
Mark Seaborn
2011/06/15 16:09:04
memcmp(), surely? The buffer is not null-terminat
Brad Chen
2011/06/15 18:47:47
Done.
|
| + // all is well |
| + g_nacl_helper_fd = fds[0]; |
| + return; |
| + } |
| + // TODO(bradchen): Make this LOG(ERROR) when the NaCl helper |
| + // becomes the default. |
| + VLOG(1) << "Could not launch NaCl helper"; |
| + g_naclpid = -1; |
| + g_nacl_helper_fd = -1; |
| + close(fds[0]); |
| + |
| + return; |
|
Mark Seaborn
2011/06/15 16:09:04
Not needed.
Brad Chen
2011/06/15 18:47:47
Done.
|
| +} |
| + |
| // With SELinux we can carve out a precise sandbox, so we don't have to play |
| // with intercepting libc calls. |
| #if !defined(CHROMIUM_SELINUX) |
| @@ -728,6 +820,9 @@ bool ZygoteMain(const MainFunctionParams& params) { |
| } |
| #endif // SECCOMP_SANDBOX |
| + // launch Native Client helper before entering the sandbox |
| + LaunchNaClHelper(); |
| + |
| // Turn on the SELinux or SUID sandbox |
| if (!EnterSandbox()) { |
| LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: " |