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: " |