diff options
author | jln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-16 19:48:20 +0000 |
---|---|---|
committer | jln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-16 19:48:20 +0000 |
commit | 43e6c36b3e5cd28e31aab94ea1ceeab3e95e62a0 (patch) | |
tree | 9af1d9a350b5ad28667f249e4c279f7a5982397e /content/common/sandbox_linux | |
parent | 4319e9191edadd125c54a6eaf531f1a47a7bdc22 (diff) | |
download | chromium_src-43e6c36b3e5cd28e31aab94ea1ceeab3e95e62a0.zip chromium_src-43e6c36b3e5cd28e31aab94ea1ceeab3e95e62a0.tar.gz chromium_src-43e6c36b3e5cd28e31aab94ea1ceeab3e95e62a0.tar.bz2 |
Sandbox Linux: add CHECK for broken promises.
GetStatus() returns the expected sandbox status, as it's typically called
before the sandbox is initialized.
Add a clear check that no broken promises have been made.
BUG=328555
R=joi@chromium.org, jorgelo@chromium.org
Review URL: https://codereview.chromium.org/115493004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@240979 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/common/sandbox_linux')
-rw-r--r-- | content/common/sandbox_linux/bpf_renderer_policy_linux.cc | 4 | ||||
-rw-r--r-- | content/common/sandbox_linux/sandbox_linux.cc | 143 | ||||
-rw-r--r-- | content/common/sandbox_linux/sandbox_linux.h | 22 |
3 files changed, 105 insertions, 64 deletions
diff --git a/content/common/sandbox_linux/bpf_renderer_policy_linux.cc b/content/common/sandbox_linux/bpf_renderer_policy_linux.cc index 461ce13..ce7dffb 100644 --- a/content/common/sandbox_linux/bpf_renderer_policy_linux.cc +++ b/content/common/sandbox_linux/bpf_renderer_policy_linux.cc @@ -34,7 +34,7 @@ RendererProcessPolicy::RendererProcessPolicy() {} RendererProcessPolicy::~RendererProcessPolicy() {} ErrorCode RendererProcessPolicy::EvaluateSyscall(SandboxBPF* sandbox, - int sysno) const { + int sysno) const { switch (sysno) { case __NR_clone: return sandbox::RestrictCloneToThreadsAndEPERMFork(sandbox); @@ -52,7 +52,7 @@ ErrorCode RendererProcessPolicy::EvaluateSyscall(SandboxBPF* sandbox, #if defined(__i386__) || defined(__arm__) case __NR_ugetrlimit: #endif - case __NR_mremap: // See crbug.com/149834. + case __NR_mremap: // See crbug.com/149834. case __NR_pread64: case __NR_pwrite64: case __NR_sched_getaffinity: diff --git a/content/common/sandbox_linux/sandbox_linux.cc b/content/common/sandbox_linux/sandbox_linux.cc index 9a8b9a8..6b14a1c 100644 --- a/content/common/sandbox_linux/sandbox_linux.cc +++ b/content/common/sandbox_linux/sandbox_linux.cc @@ -71,6 +71,7 @@ namespace content { LinuxSandbox::LinuxSandbox() : proc_fd_(-1), seccomp_bpf_started_(false), + sandbox_status_flags_(kSandboxLinuxInvalid), pre_initialized_(false), seccomp_bpf_supported_(false), setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) { @@ -120,65 +121,32 @@ void LinuxSandbox::PreinitializeSandbox() { } bool LinuxSandbox::InitializeSandbox() { - bool seccomp_bpf_started = false; LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); - // We need to make absolutely sure that our sandbox is "sealed" before - // InitializeSandbox does exit. - base::ScopedClosureRunner sandbox_sealer( - base::Bind(&LinuxSandbox::SealSandbox, base::Unretained(linux_sandbox))); - const std::string process_type = - CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kProcessType); - - // No matter what, it's always an error to call InitializeSandbox() after - // threads have been created. - if (!linux_sandbox->IsSingleThreaded()) { - std::string error_message = "InitializeSandbox() called with multiple " - "threads in process " + process_type; - // TSAN starts a helper thread. So we don't start the sandbox and don't - // even report an error about it. - if (IsRunningTSAN()) - return false; - // The GPU process is allowed to call InitializeSandbox() with threads for - // now, because it loads third party libraries. - if (process_type != switches::kGpuProcess) - CHECK(false) << error_message; - LOG(ERROR) << error_message; - return false; - } - - DCHECK(!linux_sandbox->HasOpenDirectories()) << - "InitializeSandbox() called after unexpected directories have been " << - "opened. This breaks the security of the setuid sandbox."; - - // Attempt to limit the future size of the address space of the process. - linux_sandbox->LimitAddressSpace(process_type); - - // First, try to enable seccomp-bpf. - seccomp_bpf_started = linux_sandbox->StartSeccompBPF(process_type); - - return seccomp_bpf_started; + return linux_sandbox->InitializeSandboxImpl(); } -int LinuxSandbox::GetStatus() const { +int LinuxSandbox::GetStatus() { CHECK(pre_initialized_); - int sandbox_flags = 0; - if (setuid_sandbox_client_->IsSandboxed()) { - sandbox_flags |= kSandboxLinuxSUID; - if (setuid_sandbox_client_->IsInNewPIDNamespace()) - sandbox_flags |= kSandboxLinuxPIDNS; - if (setuid_sandbox_client_->IsInNewNETNamespace()) - sandbox_flags |= kSandboxLinuxNetNS; - } + if (kSandboxLinuxInvalid == sandbox_status_flags_) { + // Initialize sandbox_status_flags_. + sandbox_status_flags_ = 0; + if (setuid_sandbox_client_->IsSandboxed()) { + sandbox_status_flags_ |= kSandboxLinuxSUID; + if (setuid_sandbox_client_->IsInNewPIDNamespace()) + sandbox_status_flags_ |= kSandboxLinuxPIDNS; + if (setuid_sandbox_client_->IsInNewNETNamespace()) + sandbox_status_flags_ |= kSandboxLinuxNetNS; + } - if (seccomp_bpf_supported() && - SandboxSeccompBPF::ShouldEnableSeccompBPF(switches::kRendererProcess)) { - // We report whether the sandbox will be activated when renderers go - // through sandbox initialization. - sandbox_flags |= kSandboxLinuxSeccompBPF; + // We report whether the sandbox will be activated when renderers, workers + // and PPAPI plugins go through sandbox initialization. + if (seccomp_bpf_supported() && + SandboxSeccompBPF::ShouldEnableSeccompBPF(switches::kRendererProcess)) { + sandbox_status_flags_ |= kSandboxLinuxSeccompBPF; + } } - return sandbox_flags; + return sandbox_status_flags_; } // Threads are counted via /proc/self/task. This is a little hairy because of @@ -228,8 +196,7 @@ sandbox::SetuidSandboxClient* // For seccomp-bpf, we use the SandboxSeccompBPF class. bool LinuxSandbox::StartSeccompBPF(const std::string& process_type) { CHECK(!seccomp_bpf_started_); - if (!pre_initialized_) - PreinitializeSandbox(); + CHECK(pre_initialized_); if (seccomp_bpf_supported()) seccomp_bpf_started_ = SandboxSeccompBPF::StartSandbox(process_type); @@ -239,6 +206,58 @@ bool LinuxSandbox::StartSeccompBPF(const std::string& process_type) { return seccomp_bpf_started_; } +bool LinuxSandbox::InitializeSandboxImpl() { + const std::string process_type = + CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kProcessType); + + // We need to make absolutely sure that our sandbox is "sealed" before + // returning. + // Unretained() since the current object is a Singleton. + base::ScopedClosureRunner sandbox_sealer( + base::Bind(&LinuxSandbox::SealSandbox, base::Unretained(this))); + // Make sure that this function enables sandboxes as promised by GetStatus(). + // Unretained() since the current object is a Singleton. + base::ScopedClosureRunner sandbox_promise_keeper( + base::Bind(&LinuxSandbox::CheckForBrokenPromises, + base::Unretained(this), + process_type)); + + // No matter what, it's always an error to call InitializeSandbox() after + // threads have been created. + if (!IsSingleThreaded()) { + std::string error_message = "InitializeSandbox() called with multiple " + "threads in process " + process_type; + // TSAN starts a helper thread. So we don't start the sandbox and don't + // even report an error about it. + if (IsRunningTSAN()) + return false; + // The GPU process is allowed to call InitializeSandbox() with threads for + // now, because it loads third-party libraries. + if (process_type != switches::kGpuProcess) + CHECK(false) << error_message; + LOG(ERROR) << error_message; + return false; + } + + // Only one thread is running, pre-initialize if not already done. + if (!pre_initialized_) + PreinitializeSandbox(); + + DCHECK(!HasOpenDirectories()) << + "InitializeSandbox() called after unexpected directories have been " << + "opened. This breaks the security of the setuid sandbox."; + + // Attempt to limit the future size of the address space of the process. + LimitAddressSpace(process_type); + + // Try to enable seccomp-bpf. + bool seccomp_bpf_started = StartSeccompBPF(process_type); + + return seccomp_bpf_started; +} + + bool LinuxSandbox::seccomp_bpf_supported() const { CHECK(pre_initialized_); return seccomp_bpf_supported_; @@ -296,5 +315,19 @@ void LinuxSandbox::SealSandbox() { } } -} // namespace content +void LinuxSandbox::CheckForBrokenPromises(const std::string& process_type) { + // Make sure that any promise made with GetStatus() wasn't broken. + bool promised_seccomp_bpf_would_start = false; + if (process_type == switches::kRendererProcess || + process_type == switches::kWorkerProcess || + process_type == switches::kPpapiPluginProcess) { + promised_seccomp_bpf_would_start = + (sandbox_status_flags_ != kSandboxLinuxInvalid) && + (GetStatus() & kSandboxLinuxSeccompBPF); + } + if (promised_seccomp_bpf_would_start) { + CHECK(seccomp_bpf_started_); + } +} +} // namespace content diff --git a/content/common/sandbox_linux/sandbox_linux.h b/content/common/sandbox_linux/sandbox_linux.h index 9afca59..da1b963 100644 --- a/content/common/sandbox_linux/sandbox_linux.h +++ b/content/common/sandbox_linux/sandbox_linux.h @@ -47,13 +47,13 @@ class LinuxSandbox { // LinuxSandbox singleton if it doesn't already exist. static bool InitializeSandbox(); - // Returns the Status of the renderers' sandbox. Can only be queried after - // going through PreinitializeSandbox(). This is a bitmask and uses the - // constants defined in "enum LinuxSandboxStatus". Since the status needs to - // be provided before the sandboxes are actually started, this returns what - // will actually happen once the various Start* functions are called from - // inside a renderer. - int GetStatus() const; + // Returns the status of the renderer, worker and ppapi sandbox. Can only + // be queried after going through PreinitializeSandbox(). This is a bitmask + // and uses the constants defined in "enum LinuxSandboxStatus". Since the + // status needs to be provided before the sandboxes are actually started, + // this returns what will actually happen once InitializeSandbox() + // is called from inside these processes. + int GetStatus(); // Returns true if the current process is single-threaded or if the number // of threads cannot be determined. bool IsSingleThreaded() const; @@ -78,6 +78,9 @@ class LinuxSandbox { private: friend struct DefaultSingletonTraits<LinuxSandbox>; + // InitializeSandbox() is static and gets an instance of the Singleton. This + // is the non-static implementation. + bool InitializeSandboxImpl(); // We must have been pre_initialized_ before using this. bool seccomp_bpf_supported() const; // Returns true if it can be determined that the current process has open @@ -87,12 +90,17 @@ class LinuxSandbox { // The last part of the initialization is to make sure any temporary "hole" // in the sandbox is closed. For now, this consists of closing proc_fd_. void SealSandbox(); + // GetStatus() makes promises as to how the sandbox will behave. This + // checks that no promises have been broken. + void CheckForBrokenPromises(const std::string& process_type); // A file descriptor to /proc. It's dangerous to have it around as it could // allow for sandbox bypasses. It needs to be closed before we consider // ourselves sandboxed. int proc_fd_; bool seccomp_bpf_started_; + // The value returned by GetStatus(). Gets computed once and then cached. + int sandbox_status_flags_; // Did PreinitializeSandbox() run? bool pre_initialized_; bool seccomp_bpf_supported_; // Accurate if pre_initialized_. |