diff options
author | jln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-02 23:14:21 +0000 |
---|---|---|
committer | jln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-02 23:14:21 +0000 |
commit | 3426ce1981d7ace455c51c5cc74fe80e5d2d5b4d (patch) | |
tree | 3d6a9e8e136bb7e09dbfc15970bdc9e48e5da727 /content/common | |
parent | 542a73f819508284ebd35a1903a6e316819e232a (diff) | |
download | chromium_src-3426ce1981d7ace455c51c5cc74fe80e5d2d5b4d.zip chromium_src-3426ce1981d7ace455c51c5cc74fe80e5d2d5b4d.tar.gz chromium_src-3426ce1981d7ace455c51c5cc74fe80e5d2d5b4d.tar.bz2 |
Create a LinuxSandbox class.
The LinuxSandbox class aims to become the central place for Linux
sandboxing inside content/.
For now, this refactors mostly code from the Zygote.
(Note: this is a re-land of https://chromiumcodereview.appspot.com/10826093/
with a trivial fix for ARM architectures).
BUG=
TBR=piman@chromium.org
NOTRY=true
Review URL: https://chromiumcodereview.appspot.com/10843059
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149734 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/common')
-rw-r--r-- | content/common/OWNERS | 2 | ||||
-rw-r--r-- | content/common/child_process_sandbox_support_impl_linux.cc | 2 | ||||
-rw-r--r-- | content/common/child_process_sandbox_support_impl_shm_linux.cc | 4 | ||||
-rw-r--r-- | content/common/sandbox_init_linux.cc | 20 | ||||
-rw-r--r-- | content/common/sandbox_linux.cc | 184 | ||||
-rw-r--r-- | content/common/sandbox_linux.h | 94 | ||||
-rw-r--r-- | content/common/sandbox_methods_linux.h | 24 | ||||
-rw-r--r-- | content/common/seccomp_sandbox.h | 24 |
8 files changed, 284 insertions, 70 deletions
diff --git a/content/common/OWNERS b/content/common/OWNERS index f8fc447..4432a1a 100644 --- a/content/common/OWNERS +++ b/content/common/OWNERS @@ -1,4 +1,4 @@ -# For sandbox_init_linux.cc +# For sandbox*_linux.* cevans@chromium.org jln@chromium.org diff --git a/content/common/child_process_sandbox_support_impl_linux.cc b/content/common/child_process_sandbox_support_impl_linux.cc index 9294e7b..8d1b8d5 100644 --- a/content/common/child_process_sandbox_support_impl_linux.cc +++ b/content/common/child_process_sandbox_support_impl_linux.cc @@ -10,7 +10,7 @@ #include "base/memory/scoped_ptr.h" #include "base/pickle.h" #include "base/posix/unix_domain_socket.h" -#include "content/common/sandbox_methods_linux.h" +#include "content/common/sandbox_linux.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/linux/WebFontFamily.h" #include "third_party/WebKit/Source/WebKit/chromium/public/linux/WebFontRenderStyle.h" diff --git a/content/common/child_process_sandbox_support_impl_shm_linux.cc b/content/common/child_process_sandbox_support_impl_shm_linux.cc index 4277382..37635df 100644 --- a/content/common/child_process_sandbox_support_impl_shm_linux.cc +++ b/content/common/child_process_sandbox_support_impl_shm_linux.cc @@ -1,11 +1,11 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/pickle.h" #include "base/posix/unix_domain_socket.h" #include "content/common/child_process_sandbox_support_impl_linux.h" -#include "content/common/sandbox_methods_linux.h" +#include "content/common/sandbox_linux.h" namespace content { diff --git a/content/common/sandbox_init_linux.cc b/content/common/sandbox_init_linux.cc index c7066c62..b9cafa2 100644 --- a/content/common/sandbox_init_linux.cc +++ b/content/common/sandbox_init_linux.cc @@ -32,6 +32,7 @@ #include "base/file_util.h" #include "base/logging.h" #include "base/time.h" +#include "content/common/sandbox_linux.h" #include "content/public/common/content_switches.h" #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" @@ -538,23 +539,6 @@ bool InitializeBpfSandbox_x86(const CommandLine& command_line, return true; } -bool InitializeLegacySandbox_x86(const CommandLine& command_line, - const std::string& process_type) { -#if defined(SECCOMP_SANDBOX) - // Start the old seccomp mode 1 (sandbox/linux/seccomp-legacy). - if (process_type == switches::kRendererProcess && SeccompSandboxEnabled()) { - // N.b. SupportsSeccompSandbox() returns a cached result, as we already - // called it earlier in the zygote. Thus, it is OK for us to not pass in - // a file descriptor for "/proc". - if (SupportsSeccompSandbox(-1)) { - StartSeccompSandbox(); - return true; - } - } -#endif - return false; -} - } // anonymous namespace #endif // defined(__i386__) || defined(__x86_64__) @@ -571,7 +555,7 @@ void InitializeSandbox() { // First, try to enable seccomp-legacy. seccomp_legacy_started = - InitializeLegacySandbox_x86(command_line, process_type); + LinuxSandbox::GetInstance()->StartSeccompLegacy(process_type); if (seccomp_legacy_started) LogSandboxStarted("seccomp-legacy", process_type); diff --git a/content/common/sandbox_linux.cc b/content/common/sandbox_linux.cc new file mode 100644 index 0000000..a0bb49a --- /dev/null +++ b/content/common/sandbox_linux.cc @@ -0,0 +1,184 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "base/command_line.h" +#include "base/eintr_wrapper.h" +#include "base/logging.h" +#include "base/memory/singleton.h" +#include "content/common/sandbox_linux.h" +#include "content/common/seccomp_sandbox.h" +#include "content/public/common/content_switches.h" +#include "content/public/common/sandbox_linux.h" +#include "sandbox/linux/suid/client/setuid_sandbox_client.h" + +#if defined(SECCOMP_BPF_SANDBOX) +#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" +#endif + +namespace { + +// Implement the command line enabling logic for seccomp-legacy. +bool IsSeccompLegacyDesired() { +#if defined(SECCOMP_SANDBOX) +#if defined(NDEBUG) + // Off by default; allow turning on with a switch. + return CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableSeccompSandbox); +#else + // On by default; allow turning off with a switch. + return !CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableSeccompSandbox); +#endif // NDEBUG +#endif // SECCOMP_SANDBOX + return false; +} + +} // namespace + +namespace content { + +LinuxSandbox::LinuxSandbox() + : proc_fd_(-1), + pre_initialized_(false), + seccomp_legacy_supported_(false), + setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) { + if (setuid_sandbox_client_ == NULL) { + LOG(FATAL) << "Failed to instantiate the setuid sandbox client."; + } +} + +LinuxSandbox::~LinuxSandbox() { +} + +LinuxSandbox* LinuxSandbox::GetInstance() { + LinuxSandbox* instance = Singleton<LinuxSandbox>::get(); + CHECK(instance); + return instance; +} + +void LinuxSandbox::PreinitializeSandboxBegin() { + CHECK(!pre_initialized_); + seccomp_legacy_supported_ = false; +#if defined(SECCOMP_SANDBOX) + if (IsSeccompLegacyDesired()) { + proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY); + if (proc_fd_ < 0) { + LOG(ERROR) << "Cannot access \"/proc\". Disabling seccomp-legacy " + "sandboxing."; + // Now is a good time to figure out if we can support seccomp sandboxing + // at all. We will call SupportsSeccompSandbox again later, when actually + // enabling it, but we allow the implementation to cache some information. + // This is the only place where we will log full lack of seccomp-legacy + // support. + } else if (!SupportsSeccompSandbox(proc_fd_)) { + VLOG(1) << "Lacking support for seccomp-legacy sandbox."; + CHECK_EQ(HANDLE_EINTR(close(proc_fd_)), 0); + proc_fd_ = -1; + } else { + seccomp_legacy_supported_ = true; + } + } +#endif // SECCOMP_SANDBOX +#if defined(SECCOMP_BPF_SANDBOX) + // Similarly, we "pre-warm" the code that detects supports for seccomp BPF. + // TODO(jln): Use proc_fd_ here too once we're comfortable it does not create + // an additional security risk. + if (playground2::Sandbox::supportsSeccompSandbox(-1) != + playground2::Sandbox::STATUS_AVAILABLE) { + VLOG(1) << "Lacking support for seccomp-bpf sandbox."; + } +#endif // SECCOMP_BPF_SANDBOX + pre_initialized_ = true; +} + +// Once we finally know our process type, we can cleanup proc_fd_ +// or pass it to seccomp-legacy. +void LinuxSandbox::PreinitializeSandboxFinish( + const std::string& process_type) { + CHECK(pre_initialized_); + if (proc_fd_ >= 0) { + if (ShouldEnableSeccompLegacy(process_type)) { +#if defined(SECCOMP_SANDBOX) + SeccompSandboxSetProcFd(proc_fd_); +#endif + } else { + DCHECK_GE(proc_fd_, 0); + CHECK_EQ(HANDLE_EINTR(close(proc_fd_)), 0); + } + proc_fd_ = -1; + } +} + +void LinuxSandbox::PreinitializeSandbox(const std::string& process_type) { + PreinitializeSandboxBegin(); + PreinitializeSandboxFinish(process_type); +} + +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 (seccomp_legacy_supported_) { + sandbox_flags |= kSandboxLinuxSeccomp; + } + return sandbox_flags; +} + +sandbox::SetuidSandboxClient* + LinuxSandbox::setuid_sandbox_client() const { + return setuid_sandbox_client_.get(); +} + +// For seccomp-legacy, we implement the policy inline, here. +bool LinuxSandbox::StartSeccompLegacy(const std::string& process_type) { + if (!pre_initialized_) + PreinitializeSandbox(process_type); + if (ShouldEnableSeccompLegacy(process_type)) { + // SupportsSeccompSandbox() returns a cached result, as we already + // called it earlier in the PreinitializeSandbox(). Thus, it is OK for us + // to not pass in a file descriptor for "/proc". +#if defined(SECCOMP_SANDBOX) + if (SupportsSeccompSandbox(-1)) { + StartSeccompSandbox(); + return true; + } +#endif + } + return false; +} + +// For seccomp-bpf, we will use the seccomp-bpf policy class. +// TODO(jln): implement this. +bool LinuxSandbox::StartSeccompBpf(const std::string& process_type) { + CHECK(pre_initialized_); + NOTREACHED(); + return false; +} + +// Our "policy" on whether or not to enable seccomp-legacy. Only renderers are +// supported. +bool LinuxSandbox::ShouldEnableSeccompLegacy( + const std::string& process_type) { + CHECK(pre_initialized_); + if (IsSeccompLegacyDesired() && + seccomp_legacy_supported_ && + process_type == switches::kRendererProcess) { + return true; + } else { + return false; + } +} + +} // namespace content + diff --git a/content/common/sandbox_linux.h b/content/common/sandbox_linux.h new file mode 100644 index 0000000..8502dfb --- /dev/null +++ b/content/common/sandbox_linux.h @@ -0,0 +1,94 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_COMMON_SANDBOX_LINUX_H_ +#define CONTENT_COMMON_SANDBOX_LINUX_H_ + +#include "base/memory/scoped_ptr.h" +#include "content/public/common/sandbox_linux.h" + +// TODO(jln) move this somewhere else. +#if defined(__i386__) || defined(__x86_64__) +#define SECCOMP_BPF_SANDBOX +#endif + +template <typename T> struct DefaultSingletonTraits; +namespace sandbox { class SetuidSandboxClient; } + +namespace content { + +// A singleton class to represent and change our sandboxing state for the +// three main Linux sandboxes. +class LinuxSandbox { + public: + // This is a list of sandbox IPC methods which the renderer may send to the + // sandbox host. See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC + // This isn't the full list, values < 32 are reserved for methods called from + // Skia. + enum LinuxSandboxIPCMethods { + METHOD_GET_FONT_FAMILY_FOR_CHARS = 32, + METHOD_LOCALTIME = 33, + METHOD_GET_CHILD_WITH_INODE = 34, + METHOD_GET_STYLE_FOR_STRIKE = 35, + METHOD_MAKE_SHARED_MEMORY_SEGMENT = 36, + METHOD_MATCH_WITH_FALLBACK = 37, + }; + + // Get our singleton instance. + static LinuxSandbox* GetInstance(); + + // Do some initialization that can only be done before any of the sandboxes + // is enabled. + // + // There are two versions of this function. One takes a process_type + // as an argument, the other doesn't. + // It may be necessary to call PreinitializeSandboxBegin before knowing the + // process type (this is for instance the case with the Zygote). + // In that case, it is crucial that PreinitializeSandboxFinish() gets + // called for every child process. + // TODO(markus,jln) we know this is not always done at the moment + // (crbug.com/139877). + void PreinitializeSandbox(const std::string& process_type); + // These should be called together. + void PreinitializeSandboxBegin(); + void PreinitializeSandboxFinish(const std::string& process_type); + + // Returns the Status of the sandbox. Can only be queried if we went through + // PreinitializeSandbox() or PreinitializeSandboxBegin(). This is a bitmask + // and uses the constants defined in "enum LinuxSandboxStatus". + // Since we need to provide the status 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(); + + // Simple accessor for our instance of the setuid sandbox. Will never return + // NULL. + // There is no StartSetuidSandbox(), the SetuidSandboxClient instance should + // be used directly. + sandbox::SetuidSandboxClient* setuid_sandbox_client() const; + + // Check the policy and eventually start the seccomp-legacy sandbox. + bool StartSeccompLegacy(const std::string& process_type); + // Check the policy and eventually start the seccomp-bpf sandbox. + // TODO(jln): not implemented at the moment. + bool StartSeccompBpf(const std::string& process_type); + + private: + friend struct DefaultSingletonTraits<LinuxSandbox>; + bool ShouldEnableSeccompLegacy(const std::string& process_type); + + int proc_fd_; + // Have we been through PreinitializeSandbox or PreinitializeSandboxBegin ? + bool pre_initialized_; + bool seccomp_legacy_supported_; // Accurate if pre_initialized_. + scoped_ptr<sandbox::SetuidSandboxClient> setuid_sandbox_client_; + LinuxSandbox(); + ~LinuxSandbox(); + DISALLOW_COPY_AND_ASSIGN(LinuxSandbox); +}; + +} // namespace content + +#endif // CONTENT_COMMON_SANDBOX_LINUX_H_ + diff --git a/content/common/sandbox_methods_linux.h b/content/common/sandbox_methods_linux.h deleted file mode 100644 index 3862b0f..0000000 --- a/content/common/sandbox_methods_linux.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_COMMON_SANDBOX_METHODS_LINUX_H_ -#define CONTENT_COMMON_SANDBOX_METHODS_LINUX_H_ - -// This is a list of sandbox IPC methods which the renderer may send to the -// sandbox host. See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC -// This isn't the full list, values < 32 are reserved for methods called from -// Skia. -class LinuxSandbox { - public: - enum Methods { - METHOD_GET_FONT_FAMILY_FOR_CHARS = 32, - METHOD_LOCALTIME = 33, - METHOD_GET_CHILD_WITH_INODE = 34, - METHOD_GET_STYLE_FOR_STRIKE = 35, - METHOD_MAKE_SHARED_MEMORY_SEGMENT = 36, - METHOD_MATCH_WITH_FALLBACK = 37, - }; -}; - -#endif // CONTENT_COMMON_SANDBOX_METHODS_LINUX_H_ diff --git a/content/common/seccomp_sandbox.h b/content/common/seccomp_sandbox.h index 0c59a11..06cf9f8 100644 --- a/content/common/seccomp_sandbox.h +++ b/content/common/seccomp_sandbox.h @@ -8,14 +8,8 @@ // Seccomp enable/disable logic is centralized here. // - We define SECCOMP_SANDBOX if seccomp is compiled in at all: currently, // on non-views (non-ChromeOS) non-ARM non-Clang Linux only. -// - If we have SECCOMP_SANDBOX, we provide SeccompSandboxEnabled() as -// a run-time test to determine whether to turn on seccomp: -// currently, on by default in debug builds and off by default in -// release. -#include "base/command_line.h" #include "build/build_config.h" -#include "content/public/common/content_switches.h" #if defined(ARCH_CPU_X86_FAMILY) && !defined(CHROMIUM_SELINUX) && \ !defined(OS_CHROMEOS) && !defined(TOOLKIT_VIEWS) && !defined(OS_OPENBSD) @@ -23,22 +17,4 @@ #include "sandbox/linux/seccomp-legacy/sandbox.h" #endif -#if defined(SECCOMP_SANDBOX) -// Return true if seccomp is enabled. -static bool SeccompSandboxEnabled() { - // TODO(evan): turn on for release too once we've flushed out all the bugs, - // allowing us to delete this file entirely and just rely on the "disabled" - // switch. -#ifdef NDEBUG - // Off by default; allow turning on with a switch. - return CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableSeccompSandbox); -#else - // On by default; allow turning off with a switch. - return !CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableSeccompSandbox); -#endif // NDEBUG -} -#endif // SECCOMP_SANDBOX - #endif // CONTENT_COMMON_SECCOMP_SANDBOX_H_ |