| Index: content/zygote/zygote_main_linux.cc
|
| diff --git a/content/zygote/zygote_main_linux.cc b/content/zygote/zygote_main_linux.cc
|
| index e70afc63928b4ab31b5045d4eeeffec746542835..6c35502c111b693b54289e3d2eaebda151bfb60c 100644
|
| --- a/content/zygote/zygote_main_linux.cc
|
| +++ b/content/zygote/zygote_main_linux.cc
|
| @@ -39,6 +39,7 @@
|
| #include "content/public/common/zygote_fork_delegate_linux.h"
|
| #include "content/zygote/zygote_linux.h"
|
| #include "crypto/nss_util.h"
|
| +#include "sandbox/linux/services/init_process_reaper.h"
|
| #include "sandbox/linux/services/libc_urandom_override.h"
|
| #include "sandbox/linux/suid/client/setuid_sandbox_client.h"
|
| #include "third_party/icu/source/i18n/unicode/timezone.h"
|
| @@ -291,7 +292,7 @@ void PreloadPepperPlugins() {
|
|
|
| // This function triggers the static and lazy construction of objects that need
|
| // to be created before imposing the sandbox.
|
| -static void PreSandboxInit() {
|
| +static void ZygotePreSandboxInit() {
|
| base::RandUint64();
|
|
|
| base::SysInfo::AmountOfPhysicalMemory();
|
| @@ -332,88 +333,102 @@ static void CloseFdAndHandleEintr(int fd) {
|
| close(fd);
|
| }
|
|
|
| -// This will set the *using_suid_sandbox variable to true if the SUID sandbox
|
| -// is enabled. This does not necessarily exclude other types of sandboxing.
|
| -static bool EnterSuidSandbox(LinuxSandbox* linux_sandbox,
|
| - bool* using_suid_sandbox,
|
| - bool* has_started_new_init) {
|
| - *using_suid_sandbox = false;
|
| - *has_started_new_init = false;
|
| +static bool CreateInitProcessReaper() {
|
| + // This "magic" socket must only appear in one process, so make sure
|
| + // it gets closed in the parent after fork().
|
| + base::Closure zygoteid_fd_closer =
|
| + base::Bind(CloseFdAndHandleEintr, kZygoteIdFd);
|
| + // The current process becomes init(1), this function returns from a
|
| + // newly created process.
|
| + const bool init_created =
|
| + sandbox::CreateInitProcessReaper(&zygoteid_fd_closer);
|
| + if (!init_created) {
|
| + LOG(ERROR) << "Error creating an init process to reap zombies";
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
|
|
| - sandbox::SetuidSandboxClient* setuid_sandbox =
|
| - linux_sandbox->setuid_sandbox_client();
|
| +// Enter the setuid sandbox. This requires the current process to have been
|
| +// created through the setuid sandbox.
|
| +static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox) {
|
| + DCHECK(setuid_sandbox);
|
| + DCHECK(setuid_sandbox->IsSuidSandboxChild());
|
| +
|
| + // Use the SUID sandbox. This still allows the seccomp sandbox to
|
| + // be enabled by the process later.
|
| +
|
| + if (!setuid_sandbox->IsSuidSandboxUpToDate()) {
|
| + LOG(WARNING) <<
|
| + "You are using a wrong version of the setuid binary!\n"
|
| + "Please read "
|
| + "https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment."
|
| + "\n\n";
|
| + }
|
|
|
| - if (!setuid_sandbox)
|
| + if (!setuid_sandbox->ChrootMe())
|
| return false;
|
|
|
| - PreSandboxInit();
|
| + if (setuid_sandbox->IsInNewPIDNamespace()) {
|
| + CHECK_EQ(1, getpid())
|
| + << "The SUID sandbox created a new PID namespace but Zygote "
|
| + "is not the init process. Please, make sure the SUID "
|
| + "binary is up to date.";
|
| + }
|
|
|
| - // Check that the pre-sandbox initialization didn't spawn threads.
|
| -#if !defined(THREAD_SANITIZER)
|
| - DCHECK(linux_sandbox->IsSingleThreaded());
|
| -#endif
|
| + if (getpid() == 1) {
|
| + // The setuid sandbox has created a new PID namespace and we need
|
| + // to assume the role of init.
|
| + CHECK(CreateInitProcessReaper());
|
| + }
|
|
|
| - if (setuid_sandbox->IsSuidSandboxChild()) {
|
| - // Use the SUID sandbox. This still allows the seccomp sandbox to
|
| - // be enabled by the process later.
|
| - *using_suid_sandbox = true;
|
| -
|
| - if (!setuid_sandbox->IsSuidSandboxUpToDate()) {
|
| - LOG(WARNING) << "You are using a wrong version of the setuid binary!\n"
|
| - "Please read "
|
| - "https://code.google.com/p/chromium/wiki/LinuxSUIDSandboxDevelopment."
|
| - "\n\n";
|
| +#if !defined(OS_OPENBSD)
|
| + // Previously, we required that the binary be non-readable. This causes the
|
| + // kernel to mark the process as non-dumpable at startup. The thinking was
|
| + // that, although we were putting the renderers into a PID namespace (with
|
| + // the SUID sandbox), they would nonetheless be in the /same/ PID
|
| + // namespace. So they could ptrace each other unless they were non-dumpable.
|
| + //
|
| + // If the binary was readable, then there would be a window between process
|
| + // startup and the point where we set the non-dumpable flag in which a
|
| + // compromised renderer could ptrace attach.
|
| + //
|
| + // However, now that we have a zygote model, only the (trusted) zygote
|
| + // exists at this point and we can set the non-dumpable flag which is
|
| + // inherited by all our renderer children.
|
| + //
|
| + // Note: a non-dumpable process can't be debugged. To debug sandbox-related
|
| + // issues, one can specify --allow-sandbox-debugging to let the process be
|
| + // dumpable.
|
| + const CommandLine& command_line = *CommandLine::ForCurrentProcess();
|
| + if (!command_line.HasSwitch(switches::kAllowSandboxDebugging)) {
|
| + prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
|
| + if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
|
| + LOG(ERROR) << "Failed to set non-dumpable flag";
|
| + return false;
|
| }
|
| + }
|
| +#endif
|
|
|
| - if (!setuid_sandbox->ChrootMe())
|
| - return false;
|
| + return true;
|
| +}
|
|
|
| - if (getpid() == 1) {
|
| - // The setuid sandbox has created a new PID namespace and we need
|
| - // to assume the role of init.
|
| - // This "magic" socket must only appear in one process, so make sure
|
| - // it gets closed in the parent after fork().
|
| - base::Closure zygoteid_fd_closer =
|
| - base::Bind(CloseFdAndHandleEintr, kZygoteIdFd);
|
| - const bool init_created =
|
| - setuid_sandbox->CreateInitProcessReaper(&zygoteid_fd_closer);
|
| - if (!init_created) {
|
| - LOG(ERROR) << "Error creating an init process to reap zombies";
|
| - return false;
|
| - }
|
| - *has_started_new_init = true;
|
| - }
|
| +static void EnterLayerOneSandbox(LinuxSandbox* linux_sandbox) {
|
| + DCHECK(linux_sandbox);
|
|
|
| -#if !defined(OS_OPENBSD)
|
| - // Previously, we required that the binary be non-readable. This causes the
|
| - // kernel to mark the process as non-dumpable at startup. The thinking was
|
| - // that, although we were putting the renderers into a PID namespace (with
|
| - // the SUID sandbox), they would nonetheless be in the /same/ PID
|
| - // namespace. So they could ptrace each other unless they were non-dumpable.
|
| - //
|
| - // If the binary was readable, then there would be a window between process
|
| - // startup and the point where we set the non-dumpable flag in which a
|
| - // compromised renderer could ptrace attach.
|
| - //
|
| - // However, now that we have a zygote model, only the (trusted) zygote
|
| - // exists at this point and we can set the non-dumpable flag which is
|
| - // inherited by all our renderer children.
|
| - //
|
| - // Note: a non-dumpable process can't be debugged. To debug sandbox-related
|
| - // issues, one can specify --allow-sandbox-debugging to let the process be
|
| - // dumpable.
|
| - const CommandLine& command_line = *CommandLine::ForCurrentProcess();
|
| - if (!command_line.HasSwitch(switches::kAllowSandboxDebugging)) {
|
| - prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
|
| - if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
|
| - LOG(ERROR) << "Failed to set non-dumpable flag";
|
| - return false;
|
| - }
|
| - }
|
| + ZygotePreSandboxInit();
|
| +
|
| + // Check that the pre-sandbox initialization didn't spawn threads.
|
| +#if !defined(THREAD_SANITIZER)
|
| + DCHECK(linux_sandbox->IsSingleThreaded());
|
| #endif
|
| - }
|
|
|
| - return true;
|
| + sandbox::SetuidSandboxClient* setuid_sandbox =
|
| + linux_sandbox->setuid_sandbox_client();
|
| +
|
| + if (setuid_sandbox->IsSuidSandboxChild()) {
|
| + CHECK(EnterSuidSandbox(setuid_sandbox)) << "Failed to enter setuid sandbox";
|
| + }
|
| }
|
|
|
| bool ZygoteMain(const MainFunctionParams& params,
|
| @@ -432,26 +447,8 @@ bool ZygoteMain(const MainFunctionParams& params,
|
| VLOG(1) << "ZygoteMain: fork delegate is NULL";
|
| }
|
|
|
| - // Turn on the sandbox.
|
| - bool using_suid_sandbox = false;
|
| - bool has_started_new_init = false;
|
| -
|
| - if (!EnterSuidSandbox(linux_sandbox,
|
| - &using_suid_sandbox,
|
| - &has_started_new_init)) {
|
| - LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: "
|
| - << errno << ")";
|
| - return false;
|
| - }
|
| -
|
| - sandbox::SetuidSandboxClient* setuid_sandbox =
|
| - linux_sandbox->setuid_sandbox_client();
|
| -
|
| - if (setuid_sandbox->IsInNewPIDNamespace() && !has_started_new_init) {
|
| - LOG(ERROR) << "The SUID sandbox created a new PID namespace but Zygote "
|
| - "is not the init process. Please, make sure the SUID "
|
| - "binary is up to date.";
|
| - }
|
| + // Turn on the first layer of the sandbox if the configuration warrants it.
|
| + EnterLayerOneSandbox(linux_sandbox);
|
|
|
| int sandbox_flags = linux_sandbox->GetStatus();
|
|
|
|
|