OLD | NEW |
---|---|
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 "content/browser/zygote_host_linux.h" | 5 #include "content/browser/zygote_host_linux.h" |
6 | 6 |
7 #include <dlfcn.h> | 7 #include <dlfcn.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <pthread.h> | 9 #include <pthread.h> |
10 #include <sys/socket.h> | 10 #include <sys/socket.h> |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
89 } | 89 } |
90 #endif // CHROMIUM_SELINUX | 90 #endif // CHROMIUM_SELINUX |
91 | 91 |
92 // This is the object which implements the zygote. The ZygoteMain function, | 92 // This is the object which implements the zygote. The ZygoteMain function, |
93 // which is called from ChromeMain, simply constructs one of these objects and | 93 // which is called from ChromeMain, simply constructs one of these objects and |
94 // runs it. | 94 // runs it. |
95 class Zygote { | 95 class Zygote { |
96 public: | 96 public: |
97 Zygote(int sandbox_flags, ZygoteForkDelegate* helper) | 97 Zygote(int sandbox_flags, ZygoteForkDelegate* helper) |
98 : sandbox_flags_(sandbox_flags), helper_(helper) { | 98 : sandbox_flags_(sandbox_flags), helper_(helper) { |
99 if (helper_) | |
100 helper_->InitialUMA(&initial_uma_name_, | |
101 &initial_uma_sample_, | |
102 &initial_uma_boundary_value_); | |
99 } | 103 } |
100 | 104 |
101 bool ProcessRequests() { | 105 bool ProcessRequests() { |
102 // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the | 106 // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the |
103 // browser on it. | 107 // browser on it. |
104 // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel. | 108 // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel. |
105 // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC | 109 // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC |
106 | 110 |
107 // We need to accept SIGCHLD, even though our handler is a no-op because | 111 // We need to accept SIGCHLD, even though our handler is a no-op because |
108 // otherwise we cannot wait on children. (According to POSIX 2001.) | 112 // otherwise we cannot wait on children. (According to POSIX 2001.) |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
246 write_pickle.WriteInt(exit_code); | 250 write_pickle.WriteInt(exit_code); |
247 ssize_t written = | 251 ssize_t written = |
248 HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size())); | 252 HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size())); |
249 if (written != static_cast<ssize_t>(write_pickle.size())) | 253 if (written != static_cast<ssize_t>(write_pickle.size())) |
250 PLOG(ERROR) << "write"; | 254 PLOG(ERROR) << "write"; |
251 } | 255 } |
252 | 256 |
253 // This is equivalent to fork(), except that, when using the SUID | 257 // This is equivalent to fork(), except that, when using the SUID |
254 // sandbox, it returns the real PID of the child process as it | 258 // sandbox, it returns the real PID of the child process as it |
255 // appears outside the sandbox, rather than returning the PID inside | 259 // appears outside the sandbox, rather than returning the PID inside |
256 // the sandbox. | 260 // the sandbox. Optionally, it fills in uma_name et al with a report |
agl
2011/10/19 16:17:27
nit: only one space after a period (at least in th
Roland McGrath
2011/10/19 18:34:15
Done.
| |
261 // the helper wants to make via UMA_HISTOGRAM_ENUMERATION. | |
257 int ForkWithRealPid(const std::string& process_type, std::vector<int>& fds, | 262 int ForkWithRealPid(const std::string& process_type, std::vector<int>& fds, |
258 const std::string& channel_switch) { | 263 const std::string& channel_switch, |
259 const bool use_helper = (helper_ && helper_->CanHelp(process_type)); | 264 std::string* uma_name, |
265 int* uma_sample, int* uma_boundary_value) { | |
266 const bool use_helper = (helper_ && helper_->CanHelp(process_type, | |
267 uma_name, | |
268 uma_sample, | |
269 uma_boundary_value)); | |
260 if (!(use_helper || g_suid_sandbox_active)) { | 270 if (!(use_helper || g_suid_sandbox_active)) { |
261 return fork(); | 271 return fork(); |
262 } | 272 } |
263 | 273 |
264 int dummy_fd; | 274 int dummy_fd; |
265 ino_t dummy_inode; | 275 ino_t dummy_inode; |
266 int pipe_fds[2] = { -1, -1 }; | 276 int pipe_fds[2] = { -1, -1 }; |
267 base::ProcessId pid = 0; | 277 base::ProcessId pid = 0; |
268 | 278 |
269 dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0); | 279 dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0); |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
375 if (pipe_fds[1] >= 0) | 385 if (pipe_fds[1] >= 0) |
376 close(pipe_fds[1]); | 386 close(pipe_fds[1]); |
377 return -1; | 387 return -1; |
378 } | 388 } |
379 | 389 |
380 // Unpacks process type and arguments from |pickle| and forks a new process. | 390 // Unpacks process type and arguments from |pickle| and forks a new process. |
381 // Returns -1 on error, otherwise returns twice, returning 0 to the child | 391 // Returns -1 on error, otherwise returns twice, returning 0 to the child |
382 // process and the child process ID to the parent process, like fork(). | 392 // process and the child process ID to the parent process, like fork(). |
383 base::ProcessId ReadArgsAndFork(const Pickle& pickle, | 393 base::ProcessId ReadArgsAndFork(const Pickle& pickle, |
384 void* iter, | 394 void* iter, |
385 std::vector<int>& fds) { | 395 std::vector<int>& fds, |
396 std::string* uma_name, | |
397 int* uma_sample, | |
398 int* uma_boundary_value) { | |
386 std::vector<std::string> args; | 399 std::vector<std::string> args; |
387 int argc = 0; | 400 int argc = 0; |
388 int numfds = 0; | 401 int numfds = 0; |
389 base::GlobalDescriptors::Mapping mapping; | 402 base::GlobalDescriptors::Mapping mapping; |
390 std::string process_type; | 403 std::string process_type; |
391 std::string channel_id; | 404 std::string channel_id; |
392 const std::string channel_id_prefix = std::string("--") | 405 const std::string channel_id_prefix = std::string("--") |
393 + switches::kProcessChannelID + std::string("="); | 406 + switches::kProcessChannelID + std::string("="); |
394 | 407 |
395 if (!pickle.ReadString(&iter, &process_type)) | 408 if (!pickle.ReadString(&iter, &process_type)) |
(...skipping 19 matching lines...) Expand all Loading... | |
415 base::GlobalDescriptors::Key key; | 428 base::GlobalDescriptors::Key key; |
416 if (!pickle.ReadUInt32(&iter, &key)) | 429 if (!pickle.ReadUInt32(&iter, &key)) |
417 return -1; | 430 return -1; |
418 mapping.push_back(std::make_pair(key, fds[i])); | 431 mapping.push_back(std::make_pair(key, fds[i])); |
419 } | 432 } |
420 | 433 |
421 mapping.push_back(std::make_pair( | 434 mapping.push_back(std::make_pair( |
422 static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor)); | 435 static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor)); |
423 | 436 |
424 // Returns twice, once per process. | 437 // Returns twice, once per process. |
425 base::ProcessId child_pid = ForkWithRealPid(process_type, fds, channel_id); | 438 base::ProcessId child_pid = ForkWithRealPid(process_type, fds, channel_id, |
439 uma_name, uma_sample, | |
440 uma_boundary_value); | |
426 if (!child_pid) { | 441 if (!child_pid) { |
427 // This is the child process. | 442 // This is the child process. |
428 #if defined(SECCOMP_SANDBOX) | 443 #if defined(SECCOMP_SANDBOX) |
429 if (SeccompSandboxEnabled() && g_proc_fd >= 0) { | 444 if (SeccompSandboxEnabled() && g_proc_fd >= 0) { |
430 // Try to open /proc/self/maps as the seccomp sandbox needs access to it | 445 // Try to open /proc/self/maps as the seccomp sandbox needs access to it |
431 int proc_self_maps = openat(g_proc_fd, "self/maps", O_RDONLY); | 446 int proc_self_maps = openat(g_proc_fd, "self/maps", O_RDONLY); |
432 if (proc_self_maps >= 0) { | 447 if (proc_self_maps >= 0) { |
433 SeccompSandboxSetProcSelfMaps(proc_self_maps); | 448 SeccompSandboxSetProcSelfMaps(proc_self_maps); |
434 } else { | 449 } else { |
435 PLOG(ERROR) << "openat(/proc/self/maps)"; | 450 PLOG(ERROR) << "openat(/proc/self/maps)"; |
(...skipping 27 matching lines...) Expand all Loading... | |
463 } | 478 } |
464 return child_pid; | 479 return child_pid; |
465 } | 480 } |
466 | 481 |
467 // Handle a 'fork' request from the browser: this means that the browser | 482 // Handle a 'fork' request from the browser: this means that the browser |
468 // wishes to start a new renderer. Returns true if we are in a new process, | 483 // wishes to start a new renderer. Returns true if we are in a new process, |
469 // otherwise writes the child_pid back to the browser via |fd|. Writes a | 484 // otherwise writes the child_pid back to the browser via |fd|. Writes a |
470 // child_pid of -1 on error. | 485 // child_pid of -1 on error. |
471 bool HandleForkRequest(int fd, const Pickle& pickle, | 486 bool HandleForkRequest(int fd, const Pickle& pickle, |
472 void* iter, std::vector<int>& fds) { | 487 void* iter, std::vector<int>& fds) { |
473 base::ProcessId child_pid = ReadArgsAndFork(pickle, iter, fds); | 488 std::string uma_name; |
489 int uma_sample; | |
490 int uma_boundary_value; | |
491 base::ProcessId child_pid = ReadArgsAndFork(pickle, iter, fds, | |
492 &uma_name, &uma_sample, | |
493 &uma_boundary_value); | |
474 if (child_pid == 0) | 494 if (child_pid == 0) |
475 return true; | 495 return true; |
476 for (std::vector<int>::const_iterator | 496 for (std::vector<int>::const_iterator |
477 i = fds.begin(); i != fds.end(); ++i) | 497 i = fds.begin(); i != fds.end(); ++i) |
478 close(*i); | 498 close(*i); |
499 if (uma_name.empty()) { | |
500 // There is no UMA report from this particular fork. | |
501 // Use the initial UMA report if any, and clear that record for next time. | |
502 uma_name.swap(initial_uma_name_); | |
agl
2011/10/19 16:17:27
Would these initial values not be returned for any
Roland McGrath
2011/10/19 18:34:15
It is cleared, as the comment says. Using swap is
| |
503 uma_sample = initial_uma_sample_; | |
504 uma_boundary_value = initial_uma_boundary_value_; | |
505 } | |
479 // Must always send reply, as ZygoteHost blocks while waiting for it. | 506 // Must always send reply, as ZygoteHost blocks while waiting for it. |
480 if (HANDLE_EINTR(write(fd, &child_pid, sizeof(child_pid))) < 0) | 507 Pickle reply_pickle; |
508 reply_pickle.WriteInt(child_pid); | |
509 reply_pickle.WriteString(uma_name); | |
510 if (!uma_name.empty()) { | |
511 reply_pickle.WriteInt(uma_sample); | |
512 reply_pickle.WriteInt(uma_boundary_value); | |
513 } | |
514 if (HANDLE_EINTR(write(fd, reply_pickle.data(), reply_pickle.size())) != | |
515 (ssize_t) reply_pickle.size()) | |
481 PLOG(ERROR) << "write"; | 516 PLOG(ERROR) << "write"; |
482 return false; | 517 return false; |
483 } | 518 } |
484 | 519 |
485 bool HandleGetSandboxStatus(int fd, const Pickle& pickle, void* iter) { | 520 bool HandleGetSandboxStatus(int fd, const Pickle& pickle, void* iter) { |
486 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_)) != | 521 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_)) != |
487 sizeof(sandbox_flags_))) { | 522 sizeof(sandbox_flags_))) { |
488 PLOG(ERROR) << "write"; | 523 PLOG(ERROR) << "write"; |
489 } | 524 } |
490 | 525 |
491 return false; | 526 return false; |
492 } | 527 } |
493 | 528 |
494 // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs | 529 // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs |
495 // fork() returns are not the real PIDs, so we need to map the Real PIDS | 530 // fork() returns are not the real PIDs, so we need to map the Real PIDS |
496 // into the sandbox PID namespace. | 531 // into the sandbox PID namespace. |
497 typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap; | 532 typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap; |
498 ProcessMap real_pids_to_sandbox_pids; | 533 ProcessMap real_pids_to_sandbox_pids; |
499 | 534 |
500 const int sandbox_flags_; | 535 const int sandbox_flags_; |
501 ZygoteForkDelegate* helper_; | 536 ZygoteForkDelegate* helper_; |
537 | |
538 // These might be set by helper_->InitialUMA. They supply a UMA | |
539 // enumeration sample we should report on the first fork. | |
540 std::string initial_uma_name_; | |
541 int initial_uma_sample_; | |
542 int initial_uma_boundary_value_; | |
502 }; | 543 }; |
503 | 544 |
504 // With SELinux we can carve out a precise sandbox, so we don't have to play | 545 // With SELinux we can carve out a precise sandbox, so we don't have to play |
505 // with intercepting libc calls. | 546 // with intercepting libc calls. |
506 #if !defined(CHROMIUM_SELINUX) | 547 #if !defined(CHROMIUM_SELINUX) |
507 | 548 |
508 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, | 549 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, |
509 char* timezone_out, | 550 char* timezone_out, |
510 size_t timezone_out_len) { | 551 size_t timezone_out_len) { |
511 Pickle request; | 552 Pickle request; |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
822 VLOG(1) << "Enabling experimental Seccomp sandbox."; | 863 VLOG(1) << "Enabling experimental Seccomp sandbox."; |
823 sandbox_flags |= ZygoteHost::kSandboxSeccomp; | 864 sandbox_flags |= ZygoteHost::kSandboxSeccomp; |
824 } | 865 } |
825 } | 866 } |
826 #endif // SECCOMP_SANDBOX | 867 #endif // SECCOMP_SANDBOX |
827 | 868 |
828 Zygote zygote(sandbox_flags, forkdelegate); | 869 Zygote zygote(sandbox_flags, forkdelegate); |
829 // This function call can return multiple times, once per fork(). | 870 // This function call can return multiple times, once per fork(). |
830 return zygote.ProcessRequests(); | 871 return zygote.ProcessRequests(); |
831 } | 872 } |
OLD | NEW |