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