OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/zygote/zygote_main.h" | 5 #include "content/zygote/zygote_main.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 <signal.h> | 10 #include <signal.h> |
(...skipping 21 matching lines...) Expand all Loading... | |
32 #include "content/common/child_process_sandbox_support_impl_linux.h" | 32 #include "content/common/child_process_sandbox_support_impl_linux.h" |
33 #include "content/common/font_config_ipc_linux.h" | 33 #include "content/common/font_config_ipc_linux.h" |
34 #include "content/common/sandbox_linux/sandbox_linux.h" | 34 #include "content/common/sandbox_linux/sandbox_linux.h" |
35 #include "content/common/zygote_commands_linux.h" | 35 #include "content/common/zygote_commands_linux.h" |
36 #include "content/public/common/content_switches.h" | 36 #include "content/public/common/content_switches.h" |
37 #include "content/public/common/main_function_params.h" | 37 #include "content/public/common/main_function_params.h" |
38 #include "content/public/common/sandbox_linux.h" | 38 #include "content/public/common/sandbox_linux.h" |
39 #include "content/public/common/zygote_fork_delegate_linux.h" | 39 #include "content/public/common/zygote_fork_delegate_linux.h" |
40 #include "content/zygote/zygote_linux.h" | 40 #include "content/zygote/zygote_linux.h" |
41 #include "crypto/nss_util.h" | 41 #include "crypto/nss_util.h" |
42 #include "sandbox/linux/services/credentials.h" | |
42 #include "sandbox/linux/services/init_process_reaper.h" | 43 #include "sandbox/linux/services/init_process_reaper.h" |
43 #include "sandbox/linux/services/libc_urandom_override.h" | 44 #include "sandbox/linux/services/libc_urandom_override.h" |
45 #include "sandbox/linux/services/namespace_sandbox.h" | |
44 #include "sandbox/linux/suid/client/setuid_sandbox_client.h" | 46 #include "sandbox/linux/suid/client/setuid_sandbox_client.h" |
45 #include "third_party/icu/source/i18n/unicode/timezone.h" | 47 #include "third_party/icu/source/i18n/unicode/timezone.h" |
46 #include "third_party/skia/include/ports/SkFontConfigInterface.h" | 48 #include "third_party/skia/include/ports/SkFontConfigInterface.h" |
47 | 49 |
48 #if defined(OS_LINUX) | 50 #if defined(OS_LINUX) |
49 #include <sys/prctl.h> | 51 #include <sys/prctl.h> |
50 #endif | 52 #endif |
51 | 53 |
52 #if defined(USE_OPENSSL) | 54 #if defined(USE_OPENSSL) |
53 #include <openssl/rand.h> | 55 #include <openssl/rand.h> |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
392 // newly created process. | 394 // newly created process. |
393 const bool init_created = | 395 const bool init_created = |
394 sandbox::CreateInitProcessReaper(post_fork_parent_callback); | 396 sandbox::CreateInitProcessReaper(post_fork_parent_callback); |
395 if (!init_created) { | 397 if (!init_created) { |
396 LOG(ERROR) << "Error creating an init process to reap zombies"; | 398 LOG(ERROR) << "Error creating an init process to reap zombies"; |
397 return false; | 399 return false; |
398 } | 400 } |
399 return true; | 401 return true; |
400 } | 402 } |
401 | 403 |
404 static bool MaybeSetProcessNonDumpable() { | |
405 // Previously, we required that the binary be non-readable. This causes the | |
406 // kernel to mark the process as non-dumpable at startup. The thinking was | |
407 // that, although we were putting the renderers into a PID namespace (with | |
408 // the SUID sandbox), they would nonetheless be in the /same/ PID | |
409 // namespace. So they could ptrace each other unless they were non-dumpable. | |
410 // | |
411 // If the binary was readable, then there would be a window between process | |
412 // startup and the point where we set the non-dumpable flag in which a | |
413 // compromised renderer could ptrace attach. | |
414 // | |
415 // However, now that we have a zygote model, only the (trusted) zygote | |
416 // exists at this point and we can set the non-dumpable flag which is | |
417 // inherited by all our renderer children. | |
418 // | |
419 // Note: a non-dumpable process can't be debugged. To debug sandbox-related | |
420 // issues, one can specify --allow-sandbox-debugging to let the process be | |
421 // dumpable. | |
422 const base::CommandLine& command_line = | |
423 *base::CommandLine::ForCurrentProcess(); | |
424 if (command_line.HasSwitch(switches::kAllowSandboxDebugging)) { | |
425 // If sandbox debugging is allowed, install a handler for sandbox-related | |
426 // crash testing. | |
427 InstallSandboxCrashTestHandler(); | |
428 return true; | |
429 } | |
430 | |
431 if (prctl(PR_SET_DUMPABLE, 0) != 0) { | |
432 PLOG(ERROR) << "Failed to set non-dumpable flag"; | |
433 return false; | |
434 } | |
435 | |
436 return prctl(PR_GET_DUMPABLE) == 0; | |
437 } | |
438 | |
402 // Enter the setuid sandbox. This requires the current process to have been | 439 // Enter the setuid sandbox. This requires the current process to have been |
403 // created through the setuid sandbox. | 440 // created through the setuid sandbox. |
404 static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox, | 441 static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox, |
405 base::Closure* post_fork_parent_callback) { | 442 base::Closure* post_fork_parent_callback) { |
406 DCHECK(setuid_sandbox); | 443 DCHECK(setuid_sandbox); |
407 DCHECK(setuid_sandbox->IsSuidSandboxChild()); | 444 DCHECK(setuid_sandbox->IsSuidSandboxChild()); |
408 | 445 |
409 // Use the SUID sandbox. This still allows the seccomp sandbox to | 446 // Use the SUID sandbox. This still allows the seccomp sandbox to |
410 // be enabled by the process later. | 447 // be enabled by the process later. |
411 | 448 |
(...skipping 14 matching lines...) Expand all Loading... | |
426 "is not the init process. Please, make sure the SUID " | 463 "is not the init process. Please, make sure the SUID " |
427 "binary is up to date."; | 464 "binary is up to date."; |
428 } | 465 } |
429 | 466 |
430 if (getpid() == 1) { | 467 if (getpid() == 1) { |
431 // The setuid sandbox has created a new PID namespace and we need | 468 // The setuid sandbox has created a new PID namespace and we need |
432 // to assume the role of init. | 469 // to assume the role of init. |
433 CHECK(CreateInitProcessReaper(post_fork_parent_callback)); | 470 CHECK(CreateInitProcessReaper(post_fork_parent_callback)); |
434 } | 471 } |
435 | 472 |
436 #if !defined(OS_OPENBSD) | 473 #if defined(OS_LINUX) |
437 // Previously, we required that the binary be non-readable. This causes the | 474 CHECK(MaybeSetProcessNonDumpable()); |
438 // kernel to mark the process as non-dumpable at startup. The thinking was | |
439 // that, although we were putting the renderers into a PID namespace (with | |
440 // the SUID sandbox), they would nonetheless be in the /same/ PID | |
441 // namespace. So they could ptrace each other unless they were non-dumpable. | |
442 // | |
443 // If the binary was readable, then there would be a window between process | |
444 // startup and the point where we set the non-dumpable flag in which a | |
445 // compromised renderer could ptrace attach. | |
446 // | |
447 // However, now that we have a zygote model, only the (trusted) zygote | |
448 // exists at this point and we can set the non-dumpable flag which is | |
449 // inherited by all our renderer children. | |
450 // | |
451 // Note: a non-dumpable process can't be debugged. To debug sandbox-related | |
452 // issues, one can specify --allow-sandbox-debugging to let the process be | |
453 // dumpable. | |
454 const base::CommandLine& command_line = | |
455 *base::CommandLine::ForCurrentProcess(); | |
456 if (!command_line.HasSwitch(switches::kAllowSandboxDebugging)) { | |
457 prctl(PR_SET_DUMPABLE, 0, 0, 0, 0); | |
458 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) { | |
459 LOG(ERROR) << "Failed to set non-dumpable flag"; | |
460 return false; | |
461 } | |
462 } else { | |
463 // If sandbox debugging is allowed, install a handler for sandbox-related | |
464 // crash testing. | |
465 InstallSandboxCrashTestHandler(); | |
466 } | |
467 | |
468 #endif | 475 #endif |
469 | 476 |
470 return true; | 477 return true; |
471 } | 478 } |
472 | 479 |
480 static void EnterNamespaceSandbox(base::Closure* post_fork_parent_callback) { | |
481 pid_t pid = getpid(); | |
482 if (sandbox::NamespaceSandbox::InNewPidNamespace()) { | |
483 CHECK_EQ(1, pid); | |
484 } | |
485 | |
486 CHECK(sandbox::Credentials::MoveToNewUserNS()); | |
487 CHECK(sandbox::Credentials::DropFileSystemAccess()); | |
488 CHECK(sandbox::Credentials::DropAllCapabilities()); | |
489 | |
490 // This needs to happen after moving to a new user NS, since doing so involves | |
491 // writing the UID/GID map. | |
492 #if defined(OS_LINUX) | |
jln (very slow on Chromium)
2015/02/06 00:37:29
At this point I think you can remove this #ifdef.
rickyz (no longer on Chrome)
2015/02/06 01:53:19
Done.
| |
493 CHECK(MaybeSetProcessNonDumpable()); | |
494 #endif | |
495 | |
496 if (pid == 1) { | |
497 CHECK(CreateInitProcessReaper(post_fork_parent_callback)); | |
498 } | |
499 } | |
500 | |
473 #if defined(ADDRESS_SANITIZER) | 501 #if defined(ADDRESS_SANITIZER) |
474 const size_t kSanitizerMaxMessageLength = 1 * 1024 * 1024; | 502 const size_t kSanitizerMaxMessageLength = 1 * 1024 * 1024; |
475 | 503 |
476 // A helper process which collects code coverage data from the renderers over a | 504 // A helper process which collects code coverage data from the renderers over a |
477 // socket and dumps it to a file. See http://crbug.com/336212 for discussion. | 505 // socket and dumps it to a file. See http://crbug.com/336212 for discussion. |
478 static void SanitizerCoverageHelper(int socket_fd, int file_fd) { | 506 static void SanitizerCoverageHelper(int socket_fd, int file_fd) { |
479 scoped_ptr<char[]> buffer(new char[kSanitizerMaxMessageLength]); | 507 scoped_ptr<char[]> buffer(new char[kSanitizerMaxMessageLength]); |
480 while (true) { | 508 while (true) { |
481 ssize_t received_size = HANDLE_EINTR( | 509 ssize_t received_size = HANDLE_EINTR( |
482 recv(socket_fd, buffer.get(), kSanitizerMaxMessageLength, 0)); | 510 recv(socket_fd, buffer.get(), kSanitizerMaxMessageLength, 0)); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
519 _exit(0); | 547 _exit(0); |
520 } else { | 548 } else { |
521 // In the parent. | 549 // In the parent. |
522 PCHECK(0 == IGNORE_EINTR(close(child_fd))); | 550 PCHECK(0 == IGNORE_EINTR(close(child_fd))); |
523 return pid; | 551 return pid; |
524 } | 552 } |
525 } | 553 } |
526 | 554 |
527 #endif // defined(ADDRESS_SANITIZER) | 555 #endif // defined(ADDRESS_SANITIZER) |
528 | 556 |
529 // If |is_suid_sandbox_child|, then make sure that the setuid sandbox is | |
530 // engaged. | |
531 static void EnterLayerOneSandbox(LinuxSandbox* linux_sandbox, | 557 static void EnterLayerOneSandbox(LinuxSandbox* linux_sandbox, |
532 bool is_suid_sandbox_child, | |
533 base::Closure* post_fork_parent_callback) { | 558 base::Closure* post_fork_parent_callback) { |
534 DCHECK(linux_sandbox); | 559 DCHECK(linux_sandbox); |
535 | 560 |
536 ZygotePreSandboxInit(); | 561 ZygotePreSandboxInit(); |
537 | 562 |
538 // Check that the pre-sandbox initialization didn't spawn threads. | 563 // Check that the pre-sandbox initialization didn't spawn threads. |
539 #if !defined(THREAD_SANITIZER) | 564 #if !defined(THREAD_SANITIZER) |
540 DCHECK(linux_sandbox->IsSingleThreaded()); | 565 DCHECK(linux_sandbox->IsSingleThreaded()); |
541 #endif | 566 #endif |
542 | 567 |
543 sandbox::SetuidSandboxClient* setuid_sandbox = | 568 sandbox::SetuidSandboxClient* setuid_sandbox = |
544 linux_sandbox->setuid_sandbox_client(); | 569 linux_sandbox->setuid_sandbox_client(); |
545 | 570 if (setuid_sandbox->IsSuidSandboxChild()) { |
546 if (is_suid_sandbox_child) { | |
547 CHECK(EnterSuidSandbox(setuid_sandbox, post_fork_parent_callback)) | 571 CHECK(EnterSuidSandbox(setuid_sandbox, post_fork_parent_callback)) |
548 << "Failed to enter setuid sandbox"; | 572 << "Failed to enter setuid sandbox"; |
573 } else if (sandbox::NamespaceSandbox::InNewUserNamespace()) { | |
574 EnterNamespaceSandbox(post_fork_parent_callback); | |
549 } | 575 } |
550 } | 576 } |
551 | 577 |
552 bool ZygoteMain(const MainFunctionParams& params, | 578 bool ZygoteMain(const MainFunctionParams& params, |
553 ScopedVector<ZygoteForkDelegate> fork_delegates) { | 579 ScopedVector<ZygoteForkDelegate> fork_delegates) { |
554 g_am_zygote_or_renderer = true; | 580 g_am_zygote_or_renderer = true; |
555 sandbox::InitLibcUrandomOverrides(); | 581 sandbox::InitLibcUrandomOverrides(); |
556 | 582 |
557 std::vector<int> fds_to_close_post_fork; | 583 std::vector<int> fds_to_close_post_fork; |
558 | 584 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
590 | 616 |
591 // Let the ZygoteHost know we're booting up. | 617 // Let the ZygoteHost know we're booting up. |
592 CHECK(UnixDomainSocket::SendMsg(kZygoteSocketPairFd, | 618 CHECK(UnixDomainSocket::SendMsg(kZygoteSocketPairFd, |
593 kZygoteBootMessage, | 619 kZygoteBootMessage, |
594 sizeof(kZygoteBootMessage), | 620 sizeof(kZygoteBootMessage), |
595 std::vector<int>())); | 621 std::vector<int>())); |
596 } | 622 } |
597 | 623 |
598 VLOG(1) << "ZygoteMain: initializing " << fork_delegates.size() | 624 VLOG(1) << "ZygoteMain: initializing " << fork_delegates.size() |
599 << " fork delegates"; | 625 << " fork delegates"; |
600 for (ScopedVector<ZygoteForkDelegate>::iterator i = fork_delegates.begin(); | 626 for (ZygoteForkDelegate* fork_delegate : fork_delegates) { |
601 i != fork_delegates.end(); | 627 fork_delegate->Init(GetSandboxFD()); |
602 ++i) { | |
603 (*i)->Init(GetSandboxFD(), must_enable_setuid_sandbox); | |
604 } | 628 } |
605 | 629 |
606 const std::vector<int> sandbox_fds_to_close_post_fork = | 630 const std::vector<int> sandbox_fds_to_close_post_fork = |
607 linux_sandbox->GetFileDescriptorsToClose(); | 631 linux_sandbox->GetFileDescriptorsToClose(); |
608 | 632 |
609 fds_to_close_post_fork.insert(fds_to_close_post_fork.end(), | 633 fds_to_close_post_fork.insert(fds_to_close_post_fork.end(), |
610 sandbox_fds_to_close_post_fork.begin(), | 634 sandbox_fds_to_close_post_fork.begin(), |
611 sandbox_fds_to_close_post_fork.end()); | 635 sandbox_fds_to_close_post_fork.end()); |
612 base::Closure post_fork_parent_callback = | 636 base::Closure post_fork_parent_callback = |
613 base::Bind(&CloseFds, fds_to_close_post_fork); | 637 base::Bind(&CloseFds, fds_to_close_post_fork); |
614 | 638 |
615 // Turn on the first layer of the sandbox if the configuration warrants it. | 639 // Turn on the first layer of the sandbox if the configuration warrants it. |
616 EnterLayerOneSandbox(linux_sandbox, must_enable_setuid_sandbox, | 640 EnterLayerOneSandbox(linux_sandbox, &post_fork_parent_callback); |
617 &post_fork_parent_callback); | |
618 | 641 |
619 // Extra children and file descriptors created that the Zygote must have | 642 // Extra children and file descriptors created that the Zygote must have |
620 // knowledge of. | 643 // knowledge of. |
621 std::vector<pid_t> extra_children; | 644 std::vector<pid_t> extra_children; |
622 std::vector<int> extra_fds; | 645 std::vector<int> extra_fds; |
623 | 646 |
624 #if defined(ADDRESS_SANITIZER) | 647 #if defined(ADDRESS_SANITIZER) |
625 pid_t sancov_helper_pid = ForkSanitizerCoverageHelper( | 648 pid_t sancov_helper_pid = ForkSanitizerCoverageHelper( |
626 sancov_socket_fds[0], sancov_socket_fds[1], sancov_file_fd.Pass(), | 649 sancov_socket_fds[0], sancov_socket_fds[1], sancov_file_fd.Pass(), |
627 sandbox_fds_to_close_post_fork); | 650 sandbox_fds_to_close_post_fork); |
(...skipping 12 matching lines...) Expand all Loading... | |
640 bool setuid_sandbox_engaged = sandbox_flags & kSandboxLinuxSUID; | 663 bool setuid_sandbox_engaged = sandbox_flags & kSandboxLinuxSUID; |
641 CHECK_EQ(must_enable_setuid_sandbox, setuid_sandbox_engaged); | 664 CHECK_EQ(must_enable_setuid_sandbox, setuid_sandbox_engaged); |
642 | 665 |
643 Zygote zygote(sandbox_flags, fork_delegates.Pass(), extra_children, | 666 Zygote zygote(sandbox_flags, fork_delegates.Pass(), extra_children, |
644 extra_fds); | 667 extra_fds); |
645 // This function call can return multiple times, once per fork(). | 668 // This function call can return multiple times, once per fork(). |
646 return zygote.ProcessRequests(); | 669 return zygote.ProcessRequests(); |
647 } | 670 } |
648 | 671 |
649 } // namespace content | 672 } // namespace content |
OLD | NEW |