summaryrefslogtreecommitdiffstats
path: root/content/common/sandbox_linux
diff options
context:
space:
mode:
authorjln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-16 19:48:20 +0000
committerjln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-16 19:48:20 +0000
commit43e6c36b3e5cd28e31aab94ea1ceeab3e95e62a0 (patch)
tree9af1d9a350b5ad28667f249e4c279f7a5982397e /content/common/sandbox_linux
parent4319e9191edadd125c54a6eaf531f1a47a7bdc22 (diff)
downloadchromium_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.cc4
-rw-r--r--content/common/sandbox_linux/sandbox_linux.cc143
-rw-r--r--content/common/sandbox_linux/sandbox_linux.h22
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_.