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 |
| 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 // Note the swap method here is the efficient way to do this, since |
| 503 // we know uma_name is empty. |
| 504 uma_name.swap(initial_uma_name_); |
| 505 uma_sample = initial_uma_sample_; |
| 506 uma_boundary_value = initial_uma_boundary_value_; |
| 507 } |
479 // Must always send reply, as ZygoteHost blocks while waiting for it. | 508 // Must always send reply, as ZygoteHost blocks while waiting for it. |
480 if (HANDLE_EINTR(write(fd, &child_pid, sizeof(child_pid))) < 0) | 509 Pickle reply_pickle; |
| 510 reply_pickle.WriteInt(child_pid); |
| 511 reply_pickle.WriteString(uma_name); |
| 512 if (!uma_name.empty()) { |
| 513 reply_pickle.WriteInt(uma_sample); |
| 514 reply_pickle.WriteInt(uma_boundary_value); |
| 515 } |
| 516 if (HANDLE_EINTR(write(fd, reply_pickle.data(), reply_pickle.size())) != |
| 517 static_cast<ssize_t> (reply_pickle.size())) |
481 PLOG(ERROR) << "write"; | 518 PLOG(ERROR) << "write"; |
482 return false; | 519 return false; |
483 } | 520 } |
484 | 521 |
485 bool HandleGetSandboxStatus(int fd, const Pickle& pickle, void* iter) { | 522 bool HandleGetSandboxStatus(int fd, const Pickle& pickle, void* iter) { |
486 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_)) != | 523 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_)) != |
487 sizeof(sandbox_flags_))) { | 524 sizeof(sandbox_flags_))) { |
488 PLOG(ERROR) << "write"; | 525 PLOG(ERROR) << "write"; |
489 } | 526 } |
490 | 527 |
491 return false; | 528 return false; |
492 } | 529 } |
493 | 530 |
494 // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs | 531 // 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 | 532 // fork() returns are not the real PIDs, so we need to map the Real PIDS |
496 // into the sandbox PID namespace. | 533 // into the sandbox PID namespace. |
497 typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap; | 534 typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap; |
498 ProcessMap real_pids_to_sandbox_pids; | 535 ProcessMap real_pids_to_sandbox_pids; |
499 | 536 |
500 const int sandbox_flags_; | 537 const int sandbox_flags_; |
501 ZygoteForkDelegate* helper_; | 538 ZygoteForkDelegate* helper_; |
| 539 |
| 540 // These might be set by helper_->InitialUMA. They supply a UMA |
| 541 // enumeration sample we should report on the first fork. |
| 542 std::string initial_uma_name_; |
| 543 int initial_uma_sample_; |
| 544 int initial_uma_boundary_value_; |
502 }; | 545 }; |
503 | 546 |
504 // With SELinux we can carve out a precise sandbox, so we don't have to play | 547 // With SELinux we can carve out a precise sandbox, so we don't have to play |
505 // with intercepting libc calls. | 548 // with intercepting libc calls. |
506 #if !defined(CHROMIUM_SELINUX) | 549 #if !defined(CHROMIUM_SELINUX) |
507 | 550 |
508 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, | 551 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, |
509 char* timezone_out, | 552 char* timezone_out, |
510 size_t timezone_out_len) { | 553 size_t timezone_out_len) { |
511 Pickle request; | 554 Pickle request; |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
822 VLOG(1) << "Enabling experimental Seccomp sandbox."; | 865 VLOG(1) << "Enabling experimental Seccomp sandbox."; |
823 sandbox_flags |= ZygoteHost::kSandboxSeccomp; | 866 sandbox_flags |= ZygoteHost::kSandboxSeccomp; |
824 } | 867 } |
825 } | 868 } |
826 #endif // SECCOMP_SANDBOX | 869 #endif // SECCOMP_SANDBOX |
827 | 870 |
828 Zygote zygote(sandbox_flags, forkdelegate); | 871 Zygote zygote(sandbox_flags, forkdelegate); |
829 // This function call can return multiple times, once per fork(). | 872 // This function call can return multiple times, once per fork(). |
830 return zygote.ProcessRequests(); | 873 return zygote.ProcessRequests(); |
831 } | 874 } |
OLD | NEW |