Commit 660e2d46 authored by rickyz's avatar rickyz Committed by Commit bot

Allow using the namespace sandbox in zygote host.

Currently, this is gated behind the enable-namespace-sandbox switch.
Furthermore, the namespace sandbox is only used if seccomp-bpf is
supported.

BUG=312380

Review URL: https://codereview.chromium.org/897723005

Cr-Commit-Position: refs/heads/master@{#315177}
parent 0264cb11
...@@ -2,6 +2,7 @@ gconf-service ...@@ -2,6 +2,7 @@ gconf-service
libasound2 (>= 1.0.23) libasound2 (>= 1.0.23)
libc6 (>= 2.11) libc6 (>= 2.11)
libcairo2 (>= 1.6.0) libcairo2 (>= 1.6.0)
libcap2 (>= 2.10)
libcups2 (>= 1.4.0) libcups2 (>= 1.4.0)
libdbus-1-3 (>= 1.2.14) libdbus-1-3 (>= 1.2.14)
libexpat1 (>= 1.95.8) libexpat1 (>= 1.95.8)
......
...@@ -2,6 +2,7 @@ gconf-service ...@@ -2,6 +2,7 @@ gconf-service
libasound2 (>= 1.0.23) libasound2 (>= 1.0.23)
libc6 (>= 2.11) libc6 (>= 2.11)
libcairo2 (>= 1.6.0) libcairo2 (>= 1.6.0)
libcap2 (>= 2.10)
libcups2 (>= 1.4.0) libcups2 (>= 1.4.0)
libdbus-1-3 (>= 1.2.14) libdbus-1-3 (>= 1.2.14)
libexpat1 (>= 1.95.8) libexpat1 (>= 1.95.8)
......
...@@ -3,6 +3,7 @@ ld-linux.so.2(GLIBC_2.1) ...@@ -3,6 +3,7 @@ ld-linux.so.2(GLIBC_2.1)
ld-linux.so.2(GLIBC_2.3) ld-linux.so.2(GLIBC_2.3)
libasound.so.2 libasound.so.2
libcairo.so.2 libcairo.so.2
libcap.so.2
libc.so.6 libc.so.6
libc.so.6(GLIBC_2.0) libc.so.6(GLIBC_2.0)
libc.so.6(GLIBC_2.1) libc.so.6(GLIBC_2.1)
......
...@@ -3,6 +3,7 @@ ld-linux-x86-64.so.2(GLIBC_2.2.5)(64bit) ...@@ -3,6 +3,7 @@ ld-linux-x86-64.so.2(GLIBC_2.2.5)(64bit)
ld-linux-x86-64.so.2(GLIBC_2.3)(64bit) ld-linux-x86-64.so.2(GLIBC_2.3)(64bit)
libasound.so.2()(64bit) libasound.so.2()(64bit)
libcairo.so.2()(64bit) libcairo.so.2()(64bit)
libcap.so.2()(64bit)
libc.so.6()(64bit) libc.so.6()(64bit)
libc.so.6(GLIBC_2.11)(64bit) libc.so.6(GLIBC_2.11)(64bit)
libc.so.6(GLIBC_2.2.5)(64bit) libc.so.6(GLIBC_2.2.5)(64bit)
......
...@@ -147,6 +147,7 @@ ...@@ -147,6 +147,7 @@
'dependencies': [ 'dependencies': [
# Required by nacl_fork_delegate_linux.cc. # Required by nacl_fork_delegate_linux.cc.
'../sandbox/sandbox.gyp:suid_sandbox_client', '../sandbox/sandbox.gyp:suid_sandbox_client',
'../sandbox/sandbox.gyp:sandbox_services',
] ]
}], }],
], ],
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include "components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.h" #include "components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#include "sandbox/linux/services/credentials.h"
#include "sandbox/linux/services/namespace_sandbox.h"
#include "sandbox/linux/services/proc_util.h" #include "sandbox/linux/services/proc_util.h"
#include "sandbox/linux/services/thread_helpers.h" #include "sandbox/linux/services/thread_helpers.h"
#include "sandbox/linux/suid/client/setuid_sandbox_client.h" #include "sandbox/linux/suid/client/setuid_sandbox_client.h"
...@@ -111,25 +113,34 @@ void NaClSandbox::InitializeLayerOneSandbox() { ...@@ -111,25 +113,34 @@ void NaClSandbox::InitializeLayerOneSandbox() {
CHECK(MaybeSetProcessNonDumpable()); CHECK(MaybeSetProcessNonDumpable());
CHECK(IsSandboxed()); CHECK(IsSandboxed());
layer_one_enabled_ = true; layer_one_enabled_ = true;
} else if (sandbox::NamespaceSandbox::InNewUserNamespace()) {
CHECK(sandbox::Credentials::MoveToNewUserNS());
CHECK(sandbox::Credentials::DropFileSystemAccess());
CHECK(sandbox::Credentials::DropAllCapabilities());
CHECK(IsSandboxed());
layer_one_enabled_ = true;
} }
} }
void NaClSandbox::CheckForExpectedNumberOfOpenFds() { void NaClSandbox::CheckForExpectedNumberOfOpenFds() {
// We expect to have the following FDs open:
// 1-3) stdin, stdout, stderr.
// 4) The /dev/urandom FD used by base::GetUrandomFD().
// 5) A dummy pipe FD used to overwrite kSandboxIPCChannel.
// 6) The socket for the Chrome IPC channel that's connected to the
// browser process, kPrimaryIPCChannel.
// We also have an fd for /proc (proc_fd_), but CountOpenFds excludes this.
//
// This sanity check ensures that dynamically loaded libraries don't
// leave any FDs open before we enable the sandbox.
int expected_num_fds = 6;
if (setuid_sandbox_client_->IsSuidSandboxChild()) { if (setuid_sandbox_client_->IsSuidSandboxChild()) {
// We expect to have the following FDs open: // When using the setuid sandbox, there is one additional socket used for
// 1-3) stdin, stdout, stderr. // ChrootMe(). After ChrootMe(), it is no longer connected to anything.
// 4) The /dev/urandom FD used by base::GetUrandomFD(). ++expected_num_fds;
// 5) A dummy pipe FD used to overwrite kSandboxIPCChannel.
// 6) The socket created by the SUID sandbox helper, used by ChrootMe().
// After ChrootMe(), this is no longer connected to anything.
// (Only present when running under the SUID sandbox.)
// 7) The socket for the Chrome IPC channel that's connected to the
// browser process, kPrimaryIPCChannel.
//
// This sanity check ensures that dynamically loaded libraries don't
// leave any FDs open before we enable the sandbox.
CHECK_EQ(7, sandbox::ProcUtil::CountOpenFds(proc_fd_.get()));
} }
CHECK_EQ(expected_num_fds, sandbox::ProcUtil::CountOpenFds(proc_fd_.get()));
} }
void NaClSandbox::InitializeLayerTwoSandbox(bool uses_nonsfi_mode) { void NaClSandbox::InitializeLayerTwoSandbox(bool uses_nonsfi_mode) {
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#include "components/nacl/loader/nacl_helper_linux.h" #include "components/nacl/loader/nacl_helper_linux.h"
#include "content/public/common/content_descriptors.h" #include "content/public/common/content_descriptors.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "sandbox/linux/services/namespace_sandbox.h"
#include "sandbox/linux/suid/client/setuid_sandbox_client.h"
#include "sandbox/linux/suid/client/setuid_sandbox_host.h" #include "sandbox/linux/suid/client/setuid_sandbox_host.h"
#include "sandbox/linux/suid/common/sandbox.h" #include "sandbox/linux/suid/common/sandbox.h"
...@@ -146,11 +148,23 @@ void NaClForkDelegate::Init(const int sandboxdesc, ...@@ -146,11 +148,23 @@ void NaClForkDelegate::Init(const int sandboxdesc,
return; return;
} }
// TODO(rickyz): Make IsSuidSandboxChild a static function.
scoped_ptr<sandbox::SetuidSandboxClient> setuid_sandbox_client(
sandbox::SetuidSandboxClient::Create());
const bool using_setuid_sandbox = setuid_sandbox_client->IsSuidSandboxChild();
const bool using_namespace_sandbox =
sandbox::NamespaceSandbox::InNewUserNamespace();
CHECK(!(using_setuid_sandbox && using_namespace_sandbox));
if (enable_layer1_sandbox) {
CHECK(using_setuid_sandbox || using_namespace_sandbox);
}
scoped_ptr<sandbox::SetuidSandboxHost> setuid_sandbox_host( scoped_ptr<sandbox::SetuidSandboxHost> setuid_sandbox_host(
sandbox::SetuidSandboxHost::Create()); sandbox::SetuidSandboxHost::Create());
// For communications between the NaCl loader process and // For communications between the NaCl loader process and
// the SUID sandbox. // the browser process.
int nacl_sandbox_descriptor = int nacl_sandbox_descriptor =
base::GlobalDescriptors::kBaseDescriptor + kSandboxIPCChannel; base::GlobalDescriptors::kBaseDescriptor + kSandboxIPCChannel;
// Confirm a hard-wired assumption. // Confirm a hard-wired assumption.
...@@ -240,7 +254,7 @@ void NaClForkDelegate::Init(const int sandboxdesc, ...@@ -240,7 +254,7 @@ void NaClForkDelegate::Init(const int sandboxdesc,
base::LaunchOptions options; base::LaunchOptions options;
base::ScopedFD dummy_fd; base::ScopedFD dummy_fd;
if (enable_layer1_sandbox) { if (using_setuid_sandbox) {
// NaCl needs to keep tight control of the cmd_line, so prepend the // NaCl needs to keep tight control of the cmd_line, so prepend the
// setuid sandbox wrapper manually. // setuid sandbox wrapper manually.
base::FilePath sandbox_path = setuid_sandbox_host->GetSandboxBinaryPath(); base::FilePath sandbox_path = setuid_sandbox_host->GetSandboxBinaryPath();
...@@ -266,11 +280,16 @@ void NaClForkDelegate::Init(const int sandboxdesc, ...@@ -266,11 +280,16 @@ void NaClForkDelegate::Init(const int sandboxdesc,
options.clear_environ = true; options.clear_environ = true;
AddPassthroughEnvToOptions(&options); AddPassthroughEnvToOptions(&options);
if (!base::LaunchProcess(argv_to_launch, options).IsValid()) base::Process process =
using_namespace_sandbox
? sandbox::NamespaceSandbox::LaunchProcess(argv_to_launch, options)
: base::LaunchProcess(argv_to_launch, options);
if (!process.IsValid())
status_ = kNaClHelperLaunchFailed; status_ = kNaClHelperLaunchFailed;
// parent and error cases are handled below // parent and error cases are handled below
if (enable_layer1_sandbox) { if (using_setuid_sandbox) {
// Sanity check that dummy_fd was kept alive for LaunchProcess. // Sanity check that dummy_fd was kept alive for LaunchProcess.
DCHECK(dummy_fd.is_valid()); DCHECK(dummy_fd.is_valid());
} }
......
...@@ -38,6 +38,9 @@ ...@@ -38,6 +38,9 @@
#include "content/public/browser/content_browser_client.h" #include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h" #include "content/public/common/result_codes.h"
#include "sandbox/linux/services/credentials.h"
#include "sandbox/linux/services/namespace_sandbox.h"
#include "sandbox/linux/services/namespace_utils.h"
#include "sandbox/linux/suid/client/setuid_sandbox_host.h" #include "sandbox/linux/suid/client/setuid_sandbox_host.h"
#include "sandbox/linux/suid/common/sandbox.h" #include "sandbox/linux/suid/common/sandbox.h"
#include "ui/base/ui_base_switches.h" #include "ui/base/ui_base_switches.h"
...@@ -49,12 +52,14 @@ ...@@ -49,12 +52,14 @@
namespace content { namespace content {
namespace {
// Receive a fixed message on fd and return the sender's PID. // Receive a fixed message on fd and return the sender's PID.
// Returns true if the message received matches the expected message. // Returns true if the message received matches the expected message.
static bool ReceiveFixedMessage(int fd, bool ReceiveFixedMessage(int fd,
const char* expect_msg, const char* expect_msg,
size_t expect_len, size_t expect_len,
base::ProcessId* sender_pid) { base::ProcessId* sender_pid) {
char buf[expect_len + 1]; char buf[expect_len + 1];
ScopedVector<base::ScopedFD> fds_vec; ScopedVector<base::ScopedFD> fds_vec;
...@@ -69,6 +74,8 @@ static bool ReceiveFixedMessage(int fd, ...@@ -69,6 +74,8 @@ static bool ReceiveFixedMessage(int fd,
return true; return true;
} }
} // namespace
// static // static
ZygoteHost* ZygoteHost::GetInstance() { ZygoteHost* ZygoteHost::GetInstance() {
return ZygoteHostImpl::GetInstance(); return ZygoteHostImpl::GetInstance();
...@@ -79,7 +86,7 @@ ZygoteHostImpl::ZygoteHostImpl() ...@@ -79,7 +86,7 @@ ZygoteHostImpl::ZygoteHostImpl()
control_lock_(), control_lock_(),
pid_(-1), pid_(-1),
init_(false), init_(false),
using_suid_sandbox_(false), use_suid_sandbox_for_adj_oom_score_(false),
sandbox_binary_(), sandbox_binary_(),
have_read_sandbox_status_word_(false), have_read_sandbox_status_word_(false),
sandbox_status_(0), sandbox_status_(0),
...@@ -141,8 +148,16 @@ void ZygoteHostImpl::Init(const std::string& sandbox_cmd) { ...@@ -141,8 +148,16 @@ void ZygoteHostImpl::Init(const std::string& sandbox_cmd) {
sandbox_binary_ = sandbox_cmd.c_str(); sandbox_binary_ = sandbox_cmd.c_str();
const bool using_namespace_sandbox = ShouldUseNamespaceSandbox();
// A non empty sandbox_cmd means we want a SUID sandbox. // A non empty sandbox_cmd means we want a SUID sandbox.
using_suid_sandbox_ = !sandbox_cmd.empty(); const bool using_suid_sandbox =
!sandbox_cmd.empty() && !using_namespace_sandbox;
// Use the SUID sandbox for adjusting OOM scores when we are using the setuid
// or namespace sandbox. This is needed beacuse the processes are
// non-dumpable, so /proc/pid/oom_score_adj can only be written by root.
use_suid_sandbox_for_adj_oom_score_ =
using_namespace_sandbox || using_suid_sandbox;
// Start up the sandbox host process and get the file descriptor for the // Start up the sandbox host process and get the file descriptor for the
// renderers to talk to it. // renderers to talk to it.
...@@ -150,7 +165,7 @@ void ZygoteHostImpl::Init(const std::string& sandbox_cmd) { ...@@ -150,7 +165,7 @@ void ZygoteHostImpl::Init(const std::string& sandbox_cmd) {
fds_to_map.push_back(std::make_pair(sfd, GetSandboxFD())); fds_to_map.push_back(std::make_pair(sfd, GetSandboxFD()));
base::ScopedFD dummy_fd; base::ScopedFD dummy_fd;
if (using_suid_sandbox_) { if (using_suid_sandbox) {
scoped_ptr<sandbox::SetuidSandboxHost> sandbox_host( scoped_ptr<sandbox::SetuidSandboxHost> sandbox_host(
sandbox::SetuidSandboxHost::Create()); sandbox::SetuidSandboxHost::Create());
sandbox_host->PrependWrapper(&cmd_line); sandbox_host->PrependWrapper(&cmd_line);
...@@ -159,11 +174,15 @@ void ZygoteHostImpl::Init(const std::string& sandbox_cmd) { ...@@ -159,11 +174,15 @@ void ZygoteHostImpl::Init(const std::string& sandbox_cmd) {
} }
options.fds_to_remap = &fds_to_map; options.fds_to_remap = &fds_to_map;
base::Process process = base::LaunchProcess(cmd_line.argv(), options); base::Process process =
using_namespace_sandbox
? sandbox::NamespaceSandbox::LaunchProcess(cmd_line, options)
: base::LaunchProcess(cmd_line, options);
CHECK(process.IsValid()) << "Failed to launch zygote process"; CHECK(process.IsValid()) << "Failed to launch zygote process";
dummy_fd.reset(); dummy_fd.reset();
if (using_suid_sandbox_) { if (using_suid_sandbox) {
// The SUID sandbox will execute the zygote in a new PID namespace, and // The SUID sandbox will execute the zygote in a new PID namespace, and
// the main zygote process will then fork from there. Watch now our // the main zygote process will then fork from there. Watch now our
// elaborate dance to find and validate the zygote's PID. // elaborate dance to find and validate the zygote's PID.
...@@ -458,7 +477,7 @@ void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid, ...@@ -458,7 +477,7 @@ void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid,
selinux_valid = true; selinux_valid = true;
} }
if (using_suid_sandbox_ && !selinux) { if (use_suid_sandbox_for_adj_oom_score_ && !selinux) {
#if defined(USE_TCMALLOC) #if defined(USE_TCMALLOC)
// If heap profiling is running, these processes are not exiting, at least // If heap profiling is running, these processes are not exiting, at least
// on ChromeOS. The easiest thing to do is not launch them when profiling. // on ChromeOS. The easiest thing to do is not launch them when profiling.
...@@ -482,7 +501,7 @@ void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid, ...@@ -482,7 +501,7 @@ void ZygoteHostImpl::AdjustRendererOOMScore(base::ProcessHandle pid,
base::LaunchProcess(adj_oom_score_cmdline, options); base::LaunchProcess(adj_oom_score_cmdline, options);
if (sandbox_helper_process.IsValid()) if (sandbox_helper_process.IsValid())
base::EnsureProcessGetsReaped(sandbox_helper_process.Pid()); base::EnsureProcessGetsReaped(sandbox_helper_process.Pid());
} else if (!using_suid_sandbox_) { } else if (!use_suid_sandbox_for_adj_oom_score_) {
if (!base::AdjustOOMScore(pid, score)) if (!base::AdjustOOMScore(pid, score))
PLOG(ERROR) << "Failed to adjust OOM score of renderer with pid " << pid; PLOG(ERROR) << "Failed to adjust OOM score of renderer with pid " << pid;
} }
...@@ -559,4 +578,22 @@ int ZygoteHostImpl::GetSandboxStatus() const { ...@@ -559,4 +578,22 @@ int ZygoteHostImpl::GetSandboxStatus() const {
return 0; return 0;
} }
bool ZygoteHostImpl::ShouldUseNamespaceSandbox() {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kNoSandbox)) {
return false;
}
if (!command_line.HasSwitch(switches::kEnableNamespaceSandbox)) {
return false;
}
if (!sandbox::Credentials::CanCreateProcessInNewUserNS()) {
return false;
}
return true;
}
} // namespace content } // namespace content
...@@ -82,6 +82,9 @@ class CONTENT_EXPORT ZygoteHostImpl : public ZygoteHost { ...@@ -82,6 +82,9 @@ class CONTENT_EXPORT ZygoteHostImpl : public ZygoteHost {
ssize_t ReadReply(void* buf, size_t buflen); ssize_t ReadReply(void* buf, size_t buflen);
// Whether we should use the namespace sandbox instead of the setuid sandbox.
bool ShouldUseNamespaceSandbox();
int control_fd_; // the socket to the zygote int control_fd_; // the socket to the zygote
// A lock protecting all communication with the zygote. This lock must be // A lock protecting all communication with the zygote. This lock must be
// acquired before sending a command and released after the result has been // acquired before sending a command and released after the result has been
...@@ -89,7 +92,7 @@ class CONTENT_EXPORT ZygoteHostImpl : public ZygoteHost { ...@@ -89,7 +92,7 @@ class CONTENT_EXPORT ZygoteHostImpl : public ZygoteHost {
base::Lock control_lock_; base::Lock control_lock_;
pid_t pid_; pid_t pid_;
bool init_; bool init_;
bool using_suid_sandbox_; bool use_suid_sandbox_for_adj_oom_score_;
std::string sandbox_binary_; std::string sandbox_binary_;
bool have_read_sandbox_status_word_; bool have_read_sandbox_status_word_;
int sandbox_status_; int sandbox_status_;
......
...@@ -357,6 +357,9 @@ const char kEnableLogging[] = "enable-logging"; ...@@ -357,6 +357,9 @@ const char kEnableLogging[] = "enable-logging";
// Enables the memory benchmarking extension // Enables the memory benchmarking extension
const char kEnableMemoryBenchmarking[] = "enable-memory-benchmarking"; const char kEnableMemoryBenchmarking[] = "enable-memory-benchmarking";
// Prefer the namespace sandbox over the setuid sandbox when possible.
const char kEnableNamespaceSandbox[] = "enable-namespace-sandbox";
// Enables the network information API. // Enables the network information API.
const char kEnableNetworkInformation[] = "enable-network-information"; const char kEnableNetworkInformation[] = "enable-network-information";
......
...@@ -110,6 +110,7 @@ CONTENT_EXPORT extern const char kEnableImageColorProfiles[]; ...@@ -110,6 +110,7 @@ CONTENT_EXPORT extern const char kEnableImageColorProfiles[];
CONTENT_EXPORT extern const char kEnableLCDText[]; CONTENT_EXPORT extern const char kEnableLCDText[];
CONTENT_EXPORT extern const char kEnableLogging[]; CONTENT_EXPORT extern const char kEnableLogging[];
extern const char kEnableMemoryBenchmarking[]; extern const char kEnableMemoryBenchmarking[];
CONTENT_EXPORT extern const char kEnableNamespaceSandbox[];
CONTENT_EXPORT extern const char kEnableNetworkInformation[]; CONTENT_EXPORT extern const char kEnableNetworkInformation[];
CONTENT_EXPORT extern const char kEnableOneCopy[]; CONTENT_EXPORT extern const char kEnableOneCopy[];
CONTENT_EXPORT extern const char kEnableOverlayFullscreenVideo[]; CONTENT_EXPORT extern const char kEnableOverlayFullscreenVideo[];
......
...@@ -39,8 +39,10 @@ ...@@ -39,8 +39,10 @@
#include "content/public/common/zygote_fork_delegate_linux.h" #include "content/public/common/zygote_fork_delegate_linux.h"
#include "content/zygote/zygote_linux.h" #include "content/zygote/zygote_linux.h"
#include "crypto/nss_util.h" #include "crypto/nss_util.h"
#include "sandbox/linux/services/credentials.h"
#include "sandbox/linux/services/init_process_reaper.h" #include "sandbox/linux/services/init_process_reaper.h"
#include "sandbox/linux/services/libc_urandom_override.h" #include "sandbox/linux/services/libc_urandom_override.h"
#include "sandbox/linux/services/namespace_sandbox.h"
#include "sandbox/linux/suid/client/setuid_sandbox_client.h" #include "sandbox/linux/suid/client/setuid_sandbox_client.h"
#include "third_party/icu/source/i18n/unicode/timezone.h" #include "third_party/icu/source/i18n/unicode/timezone.h"
#include "third_party/skia/include/ports/SkFontConfigInterface.h" #include "third_party/skia/include/ports/SkFontConfigInterface.h"
...@@ -399,6 +401,24 @@ static bool CreateInitProcessReaper(base::Closure* post_fork_parent_callback) { ...@@ -399,6 +401,24 @@ static bool CreateInitProcessReaper(base::Closure* post_fork_parent_callback) {
return true; return true;
} }
static bool MaybeSetProcessNonDumpable() {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kAllowSandboxDebugging)) {
// If sandbox debugging is allowed, install a handler for sandbox-related
// crash testing.
InstallSandboxCrashTestHandler();
return true;
}
if (prctl(PR_SET_DUMPABLE, 0) != 0) {
PLOG(ERROR) << "Failed to set non-dumpable flag";
return false;
}
return prctl(PR_GET_DUMPABLE) == 0;
}
// Enter the setuid sandbox. This requires the current process to have been // Enter the setuid sandbox. This requires the current process to have been
// created through the setuid sandbox. // created through the setuid sandbox.
static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox, static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox,
...@@ -433,41 +453,27 @@ static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox, ...@@ -433,41 +453,27 @@ static bool EnterSuidSandbox(sandbox::SetuidSandboxClient* setuid_sandbox,
CHECK(CreateInitProcessReaper(post_fork_parent_callback)); CHECK(CreateInitProcessReaper(post_fork_parent_callback));
} }
#if !defined(OS_OPENBSD) CHECK(MaybeSetProcessNonDumpable());
// Previously, we required that the binary be non-readable. This causes the return true;
// 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 static void EnterNamespaceSandbox(base::Closure* post_fork_parent_callback) {
// namespace. So they could ptrace each other unless they were non-dumpable. pid_t pid = getpid();
// if (sandbox::NamespaceSandbox::InNewPidNamespace()) {
// If the binary was readable, then there would be a window between process CHECK_EQ(1, pid);
// 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 base::CommandLine& command_line =
*base::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;
}
} else {
// If sandbox debugging is allowed, install a handler for sandbox-related
// crash testing.
InstallSandboxCrashTestHandler();
} }
#endif CHECK(sandbox::Credentials::MoveToNewUserNS());
CHECK(sandbox::Credentials::DropFileSystemAccess());
CHECK(sandbox::Credentials::DropAllCapabilities());
return true; // This needs to happen after moving to a new user NS, since doing so involves
// writing the UID/GID map.
CHECK(MaybeSetProcessNonDumpable());
if (pid == 1) {
CHECK(CreateInitProcessReaper(post_fork_parent_callback));
}
} }
#if defined(ADDRESS_SANITIZER) #if defined(ADDRESS_SANITIZER)
...@@ -526,10 +532,8 @@ static pid_t ForkSanitizerCoverageHelper( ...@@ -526,10 +532,8 @@ static pid_t ForkSanitizerCoverageHelper(
#endif // defined(ADDRESS_SANITIZER) #endif // defined(ADDRESS_SANITIZER)
// If |is_suid_sandbox_child|, then make sure that the setuid sandbox is
// engaged.
static void EnterLayerOneSandbox(LinuxSandbox* linux_sandbox, static void EnterLayerOneSandbox(LinuxSandbox* linux_sandbox,
bool is_suid_sandbox_child, const bool using_layer1_sandbox,
base::Closure* post_fork_parent_callback) { base::Closure* post_fork_parent_callback) {
DCHECK(linux_sandbox); DCHECK(linux_sandbox);
...@@ -542,10 +546,13 @@ static void EnterLayerOneSandbox(LinuxSandbox* linux_sandbox, ...@@ -542,10 +546,13 @@ static void EnterLayerOneSandbox(LinuxSandbox* linux_sandbox,
sandbox::SetuidSandboxClient* setuid_sandbox = sandbox::SetuidSandboxClient* setuid_sandbox =
linux_sandbox->setuid_sandbox_client(); linux_sandbox->setuid_sandbox_client();
if (setuid_sandbox->IsSuidSandboxChild()) {
if (is_suid_sandbox_child) {
CHECK(EnterSuidSandbox(setuid_sandbox, post_fork_parent_callback)) CHECK(EnterSuidSandbox(setuid_sandbox, post_fork_parent_callback))
<< "Failed to enter setuid sandbox"; << "Failed to enter setuid sandbox";
} else if (sandbox::NamespaceSandbox::InNewUserNamespace()) {
EnterNamespaceSandbox(post_fork_parent_callback);
} else {
CHECK(!using_layer1_sandbox);
} }
} }
...@@ -583,9 +590,12 @@ bool ZygoteMain(const MainFunctionParams& params, ...@@ -583,9 +590,12 @@ bool ZygoteMain(const MainFunctionParams& params,
linux_sandbox->PreinitializeSandbox(); linux_sandbox->PreinitializeSandbox();
} }
const bool must_enable_setuid_sandbox = const bool using_setuid_sandbox =
linux_sandbox->setuid_sandbox_client()->IsSuidSandboxChild(); linux_sandbox->setuid_sandbox_client()->IsSuidSandboxChild();
if (must_enable_setuid_sandbox) { const bool using_namespace_sandbox =
sandbox::NamespaceSandbox::InNewUserNamespace();
if (using_setuid_sandbox) {
linux_sandbox->setuid_sandbox_client()->CloseDummyFile(); linux_sandbox->setuid_sandbox_client()->CloseDummyFile();
// Let the ZygoteHost know we're booting up. // Let the ZygoteHost know we're booting up.
...@@ -597,10 +607,10 @@ bool ZygoteMain(const MainFunctionParams& params, ...@@ -597,10 +607,10 @@ bool ZygoteMain(const MainFunctionParams& params,
VLOG(1) << "ZygoteMain: initializing " << fork_delegates.size() VLOG(1) << "ZygoteMain: initializing " << fork_delegates.size()
<< " fork delegates"; << " fork delegates";
for (ScopedVector<ZygoteForkDelegate>::iterator i = fork_delegates.begin(); const bool using_layer1_sandbox =
i != fork_delegates.end(); using_setuid_sandbox || using_namespace_sandbox;
++i) { for (ZygoteForkDelegate* fork_delegate : fork_delegates) {
(*i)->Init(GetSandboxFD(), must_enable_setuid_sandbox); fork_delegate->Init(GetSandboxFD(), using_layer1_sandbox);
} }
const std::vector<int> sandbox_fds_to_close_post_fork = const std::vector<int> sandbox_fds_to_close_post_fork =
...@@ -613,7 +623,7 @@ bool ZygoteMain(const MainFunctionParams& params, ...@@ -613,7 +623,7 @@ bool ZygoteMain(const MainFunctionParams& params,
base::Bind(&CloseFds, fds_to_close_post_fork); base::Bind(&CloseFds, fds_to_close_post_fork);
// Turn on the first layer of the sandbox if the configuration warrants it. // Turn on the first layer of the sandbox if the configuration warrants it.
EnterLayerOneSandbox(linux_sandbox, must_enable_setuid_sandbox, EnterLayerOneSandbox(linux_sandbox, using_layer1_sandbox,
&post_fork_parent_callback); &post_fork_parent_callback);
// Extra children and file descriptors created that the Zygote must have // Extra children and file descriptors created that the Zygote must have
...@@ -638,7 +648,7 @@ bool ZygoteMain(const MainFunctionParams& params, ...@@ -638,7 +648,7 @@ bool ZygoteMain(const MainFunctionParams& params,
int sandbox_flags = linux_sandbox->GetStatus(); int sandbox_flags = linux_sandbox->GetStatus();
bool setuid_sandbox_engaged = sandbox_flags & kSandboxLinuxSUID; bool setuid_sandbox_engaged = sandbox_flags & kSandboxLinuxSUID;
CHECK_EQ(must_enable_setuid_sandbox, setuid_sandbox_engaged); CHECK_EQ(using_setuid_sandbox, setuid_sandbox_engaged);
Zygote zygote(sandbox_flags, fork_delegates.Pass(), extra_children, Zygote zygote(sandbox_flags, fork_delegates.Pass(), extra_children,
extra_fds); extra_fds);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector>
#include "base/command_line.h" #include "base/command_line.h"
#include "base/environment.h" #include "base/environment.h"
...@@ -59,6 +60,13 @@ const char kSandboxNETNSEnvironmentVarName[] = "SBX_NET_NS"; ...@@ -59,6 +60,13 @@ const char kSandboxNETNSEnvironmentVarName[] = "SBX_NET_NS";
base::Process NamespaceSandbox::LaunchProcess( base::Process NamespaceSandbox::LaunchProcess(
const base::CommandLine& cmdline, const base::CommandLine& cmdline,
const base::LaunchOptions& options) { const base::LaunchOptions& options) {
return LaunchProcess(cmdline.argv(), options);
}
// static
base::Process NamespaceSandbox::LaunchProcess(
const std::vector<std::string>& argv,
const base::LaunchOptions& options) {
int clone_flags = 0; int clone_flags = 0;
int ns_types[] = {CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET}; int ns_types[] = {CLONE_NEWUSER, CLONE_NEWPID, CLONE_NEWNET};
for (const int ns_type : ns_types) { for (const int ns_type : ns_types) {
...@@ -91,7 +99,7 @@ base::Process NamespaceSandbox::LaunchProcess( ...@@ -91,7 +99,7 @@ base::Process NamespaceSandbox::LaunchProcess(
SetEnvironForNamespaceType(environ, environ_name, clone_flags & flag); SetEnvironForNamespaceType(environ, environ_name, clone_flags & flag);
} }
return base::LaunchProcess(cmdline, launch_options); return base::LaunchProcess(argv, launch_options);
} }
// static // static
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
#ifndef SANDBOX_LINUX_SERVICES_NAMESPACE_SANDBOX_H_ #ifndef SANDBOX_LINUX_SERVICES_NAMESPACE_SANDBOX_H_
#define SANDBOX_LINUX_SERVICES_NAMESPACE_SANDBOX_H_ #define SANDBOX_LINUX_SERVICES_NAMESPACE_SANDBOX_H_
#include <string>
#include <vector>
#include "base/command_line.h" #include "base/command_line.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/process/launch.h" #include "base/process/launch.h"
...@@ -41,6 +44,8 @@ class SANDBOX_EXPORT NamespaceSandbox { ...@@ -41,6 +44,8 @@ class SANDBOX_EXPORT NamespaceSandbox {
// overrides them. // overrides them.
static base::Process LaunchProcess(const base::CommandLine& cmdline, static base::Process LaunchProcess(const base::CommandLine& cmdline,
const base::LaunchOptions& options); const base::LaunchOptions& options);
static base::Process LaunchProcess(const std::vector<std::string>& argv,
const base::LaunchOptions& options);
// Returns whether the namespace sandbox created a new user, PID, and network // Returns whether the namespace sandbox created a new user, PID, and network
// namespace. In particular, InNewUserNamespace should return true iff the // namespace. In particular, InNewUserNamespace should return true iff the
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment