Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(206)

Side by Side Diff: content/browser/zygote_main_linux.cc

Issue 6995121: New NaCl zygote implementation 2 (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Fixing includes for checkdeps.py Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <dlfcn.h> 5 #include <dlfcn.h>
6 #include <fcntl.h> 6 #include <fcntl.h>
7 #include <pthread.h> 7 #include <pthread.h>
8 #include <sys/epoll.h> 8 #include <sys/epoll.h>
9 #include <sys/prctl.h> 9 #include <sys/prctl.h>
10 #include <sys/signal.h> 10 #include <sys/signal.h>
(...skipping 20 matching lines...) Expand all
31 #include "base/memory/scoped_ptr.h" 31 #include "base/memory/scoped_ptr.h"
32 #include "base/path_service.h" 32 #include "base/path_service.h"
33 #include "base/pickle.h" 33 #include "base/pickle.h"
34 #include "base/process_util.h" 34 #include "base/process_util.h"
35 #include "base/rand_util.h" 35 #include "base/rand_util.h"
36 #include "base/sys_info.h" 36 #include "base/sys_info.h"
37 #include "build/build_config.h" 37 #include "build/build_config.h"
38 #include "crypto/nss_util.h" 38 #include "crypto/nss_util.h"
39 #include "chrome/common/chrome_paths.h" 39 #include "chrome/common/chrome_paths.h"
40 #include "chrome/common/chrome_switches.h" 40 #include "chrome/common/chrome_switches.h"
41 #include "chrome/common/nacl_helper_linux.h"
41 #include "content/common/chrome_descriptors.h" 42 #include "content/common/chrome_descriptors.h"
42 #include "content/common/font_config_ipc_linux.h" 43 #include "content/common/font_config_ipc_linux.h"
43 #include "content/common/main_function_params.h" 44 #include "content/common/main_function_params.h"
44 #include "content/common/pepper_plugin_registry.h" 45 #include "content/common/pepper_plugin_registry.h"
45 #include "content/common/process_watcher.h" 46 #include "content/common/process_watcher.h"
46 #include "content/common/result_codes.h" 47 #include "content/common/result_codes.h"
47 #include "content/common/sandbox_methods_linux.h" 48 #include "content/common/sandbox_methods_linux.h"
48 #include "content/common/set_process_title.h" 49 #include "content/common/set_process_title.h"
49 #include "content/common/unix_domain_socket_posix.h" 50 #include "content/common/unix_domain_socket_posix.h"
50 #include "media/base/media.h" 51 #include "media/base/media.h"
(...skipping 10 matching lines...) Expand all
61 62
62 // http://code.google.com/p/chromium/wiki/LinuxZygote 63 // http://code.google.com/p/chromium/wiki/LinuxZygote
63 64
64 static const int kBrowserDescriptor = 3; 65 static const int kBrowserDescriptor = 3;
65 static const int kMagicSandboxIPCDescriptor = 5; 66 static const int kMagicSandboxIPCDescriptor = 5;
66 static const int kZygoteIdDescriptor = 7; 67 static const int kZygoteIdDescriptor = 7;
67 static bool g_suid_sandbox_active = false; 68 static bool g_suid_sandbox_active = false;
68 #if defined(SECCOMP_SANDBOX) 69 #if defined(SECCOMP_SANDBOX)
69 // |g_proc_fd| is used only by the seccomp sandbox. 70 // |g_proc_fd| is used only by the seccomp sandbox.
70 static int g_proc_fd = -1; 71 static int g_proc_fd = -1;
72 static int g_nacl_helper_fd = -1;
73 static base::ProcessId g_naclpid = -1;
71 #endif 74 #endif
72 75
73 #if defined(CHROMIUM_SELINUX) 76 #if defined(CHROMIUM_SELINUX)
74 static void SELinuxTransitionToTypeOrDie(const char* type) { 77 static void SELinuxTransitionToTypeOrDie(const char* type) {
75 security_context_t security_context; 78 security_context_t security_context;
76 if (getcon(&security_context)) 79 if (getcon(&security_context))
77 LOG(FATAL) << "Cannot get SELinux context"; 80 LOG(FATAL) << "Cannot get SELinux context";
78 81
79 context_t context = context_new(security_context); 82 context_t context = context_new(security_context);
80 context_type_set(context, type); 83 context_type_set(context, type);
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 return false; 157 return false;
155 } 158 }
156 159
157 Pickle pickle(buf, len); 160 Pickle pickle(buf, len);
158 void* iter = NULL; 161 void* iter = NULL;
159 162
160 int kind; 163 int kind;
161 if (pickle.ReadInt(&iter, &kind)) { 164 if (pickle.ReadInt(&iter, &kind)) {
162 switch (kind) { 165 switch (kind) {
163 case ZygoteHost::kCmdFork: 166 case ZygoteHost::kCmdFork:
167 case ZygoteHost::kCmdNaClFork:
164 // This function call can return multiple times, once per fork(). 168 // This function call can return multiple times, once per fork().
165 return HandleForkRequest(fd, pickle, iter, fds); 169 return HandleForkRequest(fd, pickle, iter, fds,
170 kind == ZygoteHost::kCmdNaClFork);
166 case ZygoteHost::kCmdReap: 171 case ZygoteHost::kCmdReap:
167 if (!fds.empty()) 172 if (!fds.empty())
168 break; 173 break;
169 HandleReapRequest(fd, pickle, iter); 174 HandleReapRequest(fd, pickle, iter);
170 return false; 175 return false;
171 case ZygoteHost::kCmdGetTerminationStatus: 176 case ZygoteHost::kCmdGetTerminationStatus:
172 if (!fds.empty()) 177 if (!fds.empty())
173 break; 178 break;
174 HandleGetTerminationStatus(fd, pickle, iter); 179 HandleGetTerminationStatus(fd, pickle, iter);
175 return false; 180 return false;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 239
235 Pickle write_pickle; 240 Pickle write_pickle;
236 write_pickle.WriteInt(static_cast<int>(status)); 241 write_pickle.WriteInt(static_cast<int>(status));
237 write_pickle.WriteInt(exit_code); 242 write_pickle.WriteInt(exit_code);
238 ssize_t written = 243 ssize_t written =
239 HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size())); 244 HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size()));
240 if (written != static_cast<ssize_t>(write_pickle.size())) 245 if (written != static_cast<ssize_t>(write_pickle.size()))
241 PLOG(ERROR) << "write"; 246 PLOG(ERROR) << "write";
242 } 247 }
243 248
249 base::ProcessId ForkNaClLauncher(std::vector<int>& fds) {
250 base::ProcessId naclchild;
251 VLOG(1) << "ForkNaClLauncher";
252
253 if (g_suid_sandbox_active) {
254 DCHECK(fds.size() == kNaClParentFDIndex + 1);
255 } else {
256 DCHECK(fds.size() == kNaClSandboxFDIndex + 1);
257 }
258 if (!UnixDomainSocket::SendMsg(g_nacl_helper_fd, kNaClForkRequest,
259 sizeof(kNaClForkRequest), fds)) {
260 perror("ForkNaClLauncher: send failed");
261 return -1;
262 }
263 if (read(g_nacl_helper_fd, &naclchild, sizeof(naclchild))
264 != sizeof(naclchild)) {
265 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.
266 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
267 }
268 VLOG(1) << "nacl_child is " << naclchild;
269 return naclchild;
270 }
271
244 // This is equivalent to fork(), except that, when using the SUID 272 // This is equivalent to fork(), except that, when using the SUID
245 // sandbox, it returns the real PID of the child process as it 273 // sandbox, it returns the real PID of the child process as it
246 // appears outside the sandbox, rather than returning the PID inside 274 // appears outside the sandbox, rather than returning the PID inside
247 // the sandbox. 275 // the sandbox.
248 int ForkWithRealPid() { 276 int ForkWithRealPid(const bool naclfork, std::vector<int>& fds) {
249 if (!g_suid_sandbox_active) 277 // If we didn't start a nacl helper, don't use it to fork.
250 return fork(); 278 // TODO(bradchen): remove this once nacl helper is debugged
279 bool isnaclfork = naclfork && (g_naclpid != -1);
280
281 if (!g_suid_sandbox_active) {
282 VLOG(1) << "suid sandbox NOT active";
283 VLOG(1) << "fds.size() is " << fds.size();
284 if (isnaclfork) {
285 return ForkNaClLauncher(fds);
286 } else {
287 return fork();
288 }
289 }
251 290
252 int dummy_fd; 291 int dummy_fd;
253 ino_t dummy_inode; 292 ino_t dummy_inode;
254 int pipe_fds[2] = { -1, -1 }; 293 int pipe_fds[2] = { -1, -1 };
255 base::ProcessId pid = 0; 294 base::ProcessId pid = 0;
256 295
257 dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0); 296 dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0);
258 if (dummy_fd < 0) { 297 if (dummy_fd < 0) {
259 LOG(ERROR) << "Failed to create dummy FD"; 298 LOG(ERROR) << "Failed to create dummy FD";
260 goto error; 299 goto error;
261 } 300 }
262 if (!base::FileDescriptorGetInode(&dummy_inode, dummy_fd)) { 301 if (!base::FileDescriptorGetInode(&dummy_inode, dummy_fd)) {
263 LOG(ERROR) << "Failed to get inode for dummy FD"; 302 LOG(ERROR) << "Failed to get inode for dummy FD";
264 goto error; 303 goto error;
265 } 304 }
266 if (pipe(pipe_fds) != 0) { 305 if (pipe(pipe_fds) != 0) {
267 LOG(ERROR) << "Failed to create pipe"; 306 LOG(ERROR) << "Failed to create pipe";
268 goto error; 307 goto error;
269 } 308 }
270 309
271 pid = fork(); 310 if (isnaclfork) {
311 fds.push_back(dummy_fd);
312 fds.push_back(pipe_fds[0]);
313 pid = ForkNaClLauncher(fds);
314 } else {
315 pid = fork();
316 }
272 if (pid < 0) { 317 if (pid < 0) {
273 goto error; 318 goto error;
274 } else if (pid == 0) { 319 } else if (pid == 0) {
275 // In the child process. 320 // In the child process.
276 close(pipe_fds[1]); 321 close(pipe_fds[1]);
277 char buffer[1]; 322 char buffer[1];
278 // Wait until the parent process has discovered our PID. We 323 // Wait until the parent process has discovered our PID. We
279 // should not fork any child processes (which the seccomp 324 // should not fork any child processes (which the seccomp
280 // sandbox does) until then, because that can interfere with the 325 // sandbox does) until then, because that can interfere with the
281 // parent's discovery of our PID. 326 // parent's discovery of our PID.
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 if (pipe_fds[0] >= 0) 379 if (pipe_fds[0] >= 0)
335 close(pipe_fds[0]); 380 close(pipe_fds[0]);
336 if (pipe_fds[1] >= 0) 381 if (pipe_fds[1] >= 0)
337 close(pipe_fds[1]); 382 close(pipe_fds[1]);
338 return -1; 383 return -1;
339 } 384 }
340 385
341 // Handle a 'fork' request from the browser: this means that the browser 386 // Handle a 'fork' request from the browser: this means that the browser
342 // wishes to start a new renderer. 387 // wishes to start a new renderer.
343 bool HandleForkRequest(int fd, const Pickle& pickle, void* iter, 388 bool HandleForkRequest(int fd, const Pickle& pickle, void* iter,
344 std::vector<int>& fds) { 389 std::vector<int>& fds, const bool isnaclfork) {
345 std::vector<std::string> args; 390 std::vector<std::string> args;
346 int argc, numfds; 391 int argc, numfds;
347 base::GlobalDescriptors::Mapping mapping; 392 base::GlobalDescriptors::Mapping mapping;
348 base::ProcessId child; 393 base::ProcessId child;
349 394
350 if (!pickle.ReadInt(&iter, &argc)) 395 if (!pickle.ReadInt(&iter, &argc))
351 goto error; 396 goto error;
352 397
353 for (int i = 0; i < argc; ++i) { 398 for (int i = 0; i < argc; ++i) {
354 std::string arg; 399 std::string arg;
(...skipping 10 matching lines...) Expand all
365 for (int i = 0; i < numfds; ++i) { 410 for (int i = 0; i < numfds; ++i) {
366 base::GlobalDescriptors::Key key; 411 base::GlobalDescriptors::Key key;
367 if (!pickle.ReadUInt32(&iter, &key)) 412 if (!pickle.ReadUInt32(&iter, &key))
368 goto error; 413 goto error;
369 mapping.push_back(std::make_pair(key, fds[i])); 414 mapping.push_back(std::make_pair(key, fds[i]));
370 } 415 }
371 416
372 mapping.push_back(std::make_pair( 417 mapping.push_back(std::make_pair(
373 static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor)); 418 static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor));
374 419
375 child = ForkWithRealPid(); 420 if (isnaclfork) {
421 fds.push_back(kMagicSandboxIPCDescriptor);
422 }
423 child = ForkWithRealPid(isnaclfork, fds);
376 424
377 if (!child) { 425 if (!child) {
378 #if defined(SECCOMP_SANDBOX) 426 #if defined(SECCOMP_SANDBOX)
379 // Try to open /proc/self/maps as the seccomp sandbox needs access to it 427 // Try to open /proc/self/maps as the seccomp sandbox needs access to it
380 if (g_proc_fd >= 0) { 428 if (g_proc_fd >= 0) {
381 int proc_self_maps = openat(g_proc_fd, "self/maps", O_RDONLY); 429 int proc_self_maps = openat(g_proc_fd, "self/maps", O_RDONLY);
382 if (proc_self_maps >= 0) { 430 if (proc_self_maps >= 0) {
383 SeccompSandboxSetProcSelfMaps(proc_self_maps); 431 SeccompSandboxSetProcSelfMaps(proc_self_maps);
384 } 432 }
385 close(g_proc_fd); 433 close(g_proc_fd);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 488
441 // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs 489 // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs
442 // fork() returns are not the real PIDs, so we need to map the Real PIDS 490 // fork() returns are not the real PIDs, so we need to map the Real PIDS
443 // into the sandbox PID namespace. 491 // into the sandbox PID namespace.
444 typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap; 492 typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap;
445 ProcessMap real_pids_to_sandbox_pids; 493 ProcessMap real_pids_to_sandbox_pids;
446 494
447 const int sandbox_flags_; 495 const int sandbox_flags_;
448 }; 496 };
449 497
498 static void LaunchNaClHelper() {
499 VLOG(1) << "LaunchNaClHelper";
500 int fds[2];
501
502 // Confirm a couple hard-wired assumptions.
503 // The NaCl constants are from chrome/nacl/nacl_linux_helper.h
504 DCHECK(kNaClZygoteDescriptor == kBrowserDescriptor);
505 DCHECK(kNaClSandboxDescriptor == kMagicSandboxIPCDescriptor);
506
507 CHECK(socketpair(PF_UNIX, SOCK_SEQPACKET, 0, fds) == 0);
508 base::file_handle_mapping_vector fds_to_map;
509 fds_to_map.push_back(std::make_pair(fds[1], 3));
510
511 const char* nacl_zygote_exe = getenv("NACL_NEW_ZYGOTE");
512 g_naclpid = -1;
513 if (NULL != nacl_zygote_exe) {
514 CommandLine::StringVector argv = CommandLine::ForCurrentProcess()->argv();
515 argv[0] = nacl_zygote_exe;
516 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
517 CLONE_FS | SIGCHLD);
518 }
519 close(fds[1]);
520 if (g_naclpid > 0) {
521 const int kExpectedLength = sizeof(kNaClHelperMagic);
522 char buf[kExpectedLength];
523
524 VLOG(1) << "NaCl Launcher PID is " << g_naclpid;
525 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.
526 DCHECK(nread == kExpectedLength) << "Incorrect NaCl helper magic length";
527 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.
528 // all is well
529 g_nacl_helper_fd = fds[0];
530 return;
531 }
532 // TODO(bradchen): Make this LOG(ERROR) when the NaCl helper
533 // becomes the default.
534 VLOG(1) << "Could not launch NaCl helper";
535 g_naclpid = -1;
536 g_nacl_helper_fd = -1;
537 close(fds[0]);
538
539 return;
Mark Seaborn 2011/06/15 16:09:04 Not needed.
Brad Chen 2011/06/15 18:47:47 Done.
540 }
541
450 // With SELinux we can carve out a precise sandbox, so we don't have to play 542 // With SELinux we can carve out a precise sandbox, so we don't have to play
451 // with intercepting libc calls. 543 // with intercepting libc calls.
452 #if !defined(CHROMIUM_SELINUX) 544 #if !defined(CHROMIUM_SELINUX)
453 545
454 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, 546 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output,
455 char* timezone_out, 547 char* timezone_out,
456 size_t timezone_out_len) { 548 size_t timezone_out_len) {
457 Pickle request; 549 Pickle request;
458 request.WriteInt(LinuxSandbox::METHOD_LOCALTIME); 550 request.WriteInt(LinuxSandbox::METHOD_LOCALTIME);
459 request.WriteString( 551 request.WriteString(
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after
721 if (CommandLine::ForCurrentProcess()->HasSwitch( 813 if (CommandLine::ForCurrentProcess()->HasSwitch(
722 switches::kEnableSeccompSandbox)) { 814 switches::kEnableSeccompSandbox)) {
723 g_proc_fd = open("/proc", O_DIRECTORY | O_RDONLY); 815 g_proc_fd = open("/proc", O_DIRECTORY | O_RDONLY);
724 if (g_proc_fd < 0) { 816 if (g_proc_fd < 0) {
725 LOG(ERROR) << "WARNING! Cannot access \"/proc\". Disabling seccomp " 817 LOG(ERROR) << "WARNING! Cannot access \"/proc\". Disabling seccomp "
726 "sandboxing."; 818 "sandboxing.";
727 } 819 }
728 } 820 }
729 #endif // SECCOMP_SANDBOX 821 #endif // SECCOMP_SANDBOX
730 822
823 // launch Native Client helper before entering the sandbox
824 LaunchNaClHelper();
825
731 // Turn on the SELinux or SUID sandbox 826 // Turn on the SELinux or SUID sandbox
732 if (!EnterSandbox()) { 827 if (!EnterSandbox()) {
733 LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: " 828 LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: "
734 << errno << ")"; 829 << errno << ")";
735 return false; 830 return false;
736 } 831 }
737 832
738 int sandbox_flags = 0; 833 int sandbox_flags = 0;
739 if (getenv("SBX_D")) 834 if (getenv("SBX_D"))
740 sandbox_flags |= ZygoteHost::kSandboxSUID; 835 sandbox_flags |= ZygoteHost::kSandboxSUID;
(...skipping 20 matching lines...) Expand all
761 VLOG(1) << "Enabling experimental Seccomp sandbox."; 856 VLOG(1) << "Enabling experimental Seccomp sandbox.";
762 sandbox_flags |= ZygoteHost::kSandboxSeccomp; 857 sandbox_flags |= ZygoteHost::kSandboxSeccomp;
763 } 858 }
764 } 859 }
765 #endif // SECCOMP_SANDBOX 860 #endif // SECCOMP_SANDBOX
766 861
767 Zygote zygote(sandbox_flags); 862 Zygote zygote(sandbox_flags);
768 // This function call can return multiple times, once per fork(). 863 // This function call can return multiple times, once per fork().
769 return zygote.ProcessRequests(); 864 return zygote.ProcessRequests();
770 } 865 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698