summaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorjln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-29 01:53:54 +0000
committerjln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-29 01:53:54 +0000
commit55a2bbe1957e00edf7dba29ff89bc33cae83a113 (patch)
treeefb3cc88577ad6674b848d4f69541d2d8122bb82 /components
parent6fbe13e22bf1f3fbaea24cd1a219af56b546966c (diff)
downloadchromium_src-55a2bbe1957e00edf7dba29ff89bc33cae83a113.zip
chromium_src-55a2bbe1957e00edf7dba29ff89bc33cae83a113.tar.gz
chromium_src-55a2bbe1957e00edf7dba29ff89bc33cae83a113.tar.bz2
NaCl Linux: create NaClSandbox class
We create a new NaClSandbox class, with InitializeLayerOneSandbox() and InitializeLayerTwoSandbox() methods. This class centralizes existing code and adds important security checks as to whether or not threads are running or directory file descriptors are open. BUG=359230, 358719 R=mseaborn@chromium.org Review URL: https://codereview.chromium.org/250773003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266735 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components')
-rw-r--r--components/nacl.gyp3
-rw-r--r--components/nacl/loader/OWNERS2
-rw-r--r--components/nacl/loader/nacl_helper_linux.cc112
-rw-r--r--components/nacl/loader/nacl_sandbox_linux.h10
-rw-r--r--components/nacl/loader/sandbox_linux/OWNERS2
-rw-r--r--components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.cc (renamed from components/nacl/loader/nacl_sandbox_linux.cc)6
-rw-r--r--components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.h14
-rw-r--r--components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc148
-rw-r--r--components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h76
9 files changed, 277 insertions, 96 deletions
diff --git a/components/nacl.gyp b/components/nacl.gyp
index 883db8b..27fbea1 100644
--- a/components/nacl.gyp
+++ b/components/nacl.gyp
@@ -225,7 +225,6 @@
'IN_NACL_HELPER=1',
],
'sources': [
- 'nacl/loader/nacl_sandbox_linux.cc',
'nacl/loader/nonsfi/abi_conversion.cc',
'nacl/loader/nonsfi/abi_conversion.h',
'nacl/loader/nonsfi/elf_loader.cc',
@@ -245,6 +244,8 @@
'nacl/loader/nonsfi/nonsfi_main.h',
'nacl/loader/nonsfi/nonsfi_sandbox.cc',
'nacl/loader/nonsfi/nonsfi_sandbox.h',
+ 'nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.cc',
+ 'nacl/loader/sandbox_linux/nacl_sandbox_linux.cc',
'../ppapi/nacl_irt/manifest_service.cc',
'../ppapi/nacl_irt/manifest_service.h',
'../ppapi/nacl_irt/plugin_main.cc',
diff --git a/components/nacl/loader/OWNERS b/components/nacl/loader/OWNERS
deleted file mode 100644
index 9693b6b..0000000
--- a/components/nacl/loader/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file nacl_sandbox_linux.*=jln@chromium.org
-per-file nacl_sandbox_linux.*=mseaborn@chromium.org
diff --git a/components/nacl/loader/nacl_helper_linux.cc b/components/nacl/loader/nacl_helper_linux.cc
index a7c6615..68d0ff6 100644
--- a/components/nacl/loader/nacl_helper_linux.cc
+++ b/components/nacl/loader/nacl_helper_linux.cc
@@ -32,17 +32,13 @@
#include "base/rand_util.h"
#include "components/nacl/common/nacl_switches.h"
#include "components/nacl/loader/nacl_listener.h"
-#include "components/nacl/loader/nacl_sandbox_linux.h"
-#include "components/nacl/loader/nonsfi/nonsfi_sandbox.h"
+#include "components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h"
#include "content/public/common/content_descriptors.h"
#include "content/public/common/zygote_fork_delegate_linux.h"
#include "crypto/nss_util.h"
#include "ipc/ipc_descriptors.h"
#include "ipc/ipc_switches.h"
-#include "sandbox/linux/services/credentials.h"
#include "sandbox/linux/services/libc_urandom_override.h"
-#include "sandbox/linux/services/thread_helpers.h"
-#include "sandbox/linux/suid/client/setuid_sandbox_client.h"
namespace {
@@ -51,69 +47,6 @@ struct NaClLoaderSystemInfo {
long number_of_cores;
};
-// This is a poor man's check on whether we are sandboxed.
-bool IsSandboxed() {
- int proc_fd = open("/proc/self/exe", O_RDONLY);
- if (proc_fd >= 0) {
- close(proc_fd);
- return false;
- }
- return true;
-}
-
-void InitializeLayerOneSandbox() {
- // Check that IsSandboxed() works. We should not be sandboxed at this point.
- CHECK(!IsSandboxed()) << "Unexpectedly sandboxed!";
- scoped_ptr<sandbox::SetuidSandboxClient>
- setuid_sandbox_client(sandbox::SetuidSandboxClient::Create());
- PCHECK(0 == IGNORE_EINTR(close(
- setuid_sandbox_client->GetUniqueToChildFileDescriptor())));
- const bool suid_sandbox_child = setuid_sandbox_client->IsSuidSandboxChild();
- const bool is_init_process = 1 == getpid();
- CHECK_EQ(is_init_process, suid_sandbox_child);
-
- if (suid_sandbox_child) {
- // Make sure that no directory file descriptor is open, as it would bypass
- // the setuid sandbox model.
- sandbox::Credentials credentials;
- CHECK(!credentials.HasOpenDirectory(-1));
-
- // Get sandboxed.
- CHECK(setuid_sandbox_client->ChrootMe());
- CHECK(IsSandboxed());
- }
-}
-
-void InitializeLayerTwoSandbox(bool uses_nonsfi_mode) {
- if (uses_nonsfi_mode) {
- const bool can_be_no_sandbox = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kNaClDangerousNoSandboxNonSfi);
- const bool setuid_sandbox_enabled = IsSandboxed();
- if (!setuid_sandbox_enabled) {
- if (can_be_no_sandbox)
- LOG(ERROR) << "DANGEROUS: Running non-SFI NaCl without SUID sandbox!";
- else
- LOG(FATAL) << "SUID sandbox is mandatory for non-SFI NaCl";
- }
- const bool bpf_sandbox_initialized = nacl::nonsfi::InitializeBPFSandbox();
- if (!bpf_sandbox_initialized) {
- if (can_be_no_sandbox) {
- LOG(ERROR)
- << "DANGEROUS: Running non-SFI NaCl without seccomp-bpf sandbox!";
- } else {
- LOG(FATAL) << "Could not initialize NaCl's second "
- << "layer sandbox (seccomp-bpf) for non-SFI mode.";
- }
- }
- } else {
- const bool bpf_sandbox_initialized = InitializeBPFSandbox();
- if (!bpf_sandbox_initialized) {
- LOG(ERROR) << "Could not initialize NaCl's second "
- << "layer sandbox (seccomp-bpf) for SFI mode.";
- }
- }
-}
-
// Replace |file_descriptor| with the reading end of a closed pipe.
void ReplaceFDWithDummy(int file_descriptor) {
// Make sure that file_descriptor is an open descriptor.
@@ -130,7 +63,9 @@ void ReplaceFDWithDummy(int file_descriptor) {
// if (!child) {
void BecomeNaClLoader(const std::vector<int>& child_fds,
const NaClLoaderSystemInfo& system_info,
- bool uses_nonsfi_mode) {
+ bool uses_nonsfi_mode,
+ nacl::NaClSandbox* nacl_sandbox) {
+ DCHECK(nacl_sandbox);
VLOG(1) << "NaCl loader: setting up IPC descriptor";
// Close or shutdown IPC channels that we don't need anymore.
PCHECK(0 == IGNORE_EINTR(close(kNaClZygoteDescriptor)));
@@ -149,7 +84,12 @@ void BecomeNaClLoader(const std::vector<int>& child_fds,
ReplaceFDWithDummy(sandbox_ipc_channel);
}
- InitializeLayerTwoSandbox(uses_nonsfi_mode);
+ // Finish layer-1 sandbox initialization and initialize the layer-2 sandbox.
+ CHECK(!nacl_sandbox->HasOpenDirectory());
+ nacl_sandbox->InitializeLayerTwoSandbox(uses_nonsfi_mode);
+ nacl_sandbox->SealLayerOneSandbox();
+ nacl_sandbox->CheckSandboxingStateWithPolicy();
+
base::GlobalDescriptors::GetInstance()->Set(
kPrimaryIPCChannel,
child_fds[content::ZygoteForkDelegate::kBrowserFDIndex]);
@@ -167,6 +107,7 @@ void BecomeNaClLoader(const std::vector<int>& child_fds,
void ChildNaClLoaderInit(const std::vector<int>& child_fds,
const NaClLoaderSystemInfo& system_info,
bool uses_nonsfi_mode,
+ nacl::NaClSandbox* nacl_sandbox,
const std::string& channel_id) {
const int parent_fd = child_fds[content::ZygoteForkDelegate::kParentFDIndex];
const int dummy_fd = child_fds[content::ZygoteForkDelegate::kDummyFDIndex];
@@ -199,7 +140,7 @@ void ChildNaClLoaderInit(const std::vector<int>& child_fds,
if (IGNORE_EINTR(close(parent_fd)) != 0)
LOG(ERROR) << "close(parent_fd) failed";
if (validack) {
- BecomeNaClLoader(child_fds, system_info, uses_nonsfi_mode);
+ BecomeNaClLoader(child_fds, system_info, uses_nonsfi_mode, nacl_sandbox);
} else {
LOG(ERROR) << "Failed to synch with zygote";
}
@@ -211,6 +152,7 @@ void ChildNaClLoaderInit(const std::vector<int>& child_fds,
// content/browser/zygote_main_linux.cc:ForkWithRealPid()
bool HandleForkRequest(const std::vector<int>& child_fds,
const NaClLoaderSystemInfo& system_info,
+ nacl::NaClSandbox* nacl_sandbox,
PickleIterator* input_iter,
Pickle* output_pickle) {
bool uses_nonsfi_mode;
@@ -238,7 +180,8 @@ bool HandleForkRequest(const std::vector<int>& child_fds,
}
if (child_pid == 0) {
- ChildNaClLoaderInit(child_fds, system_info, uses_nonsfi_mode, channel_id);
+ ChildNaClLoaderInit(
+ child_fds, system_info, uses_nonsfi_mode, nacl_sandbox, channel_id);
NOTREACHED();
}
@@ -293,14 +236,15 @@ bool HonorRequestAndReply(int reply_fd,
int command_type,
const std::vector<int>& attached_fds,
const NaClLoaderSystemInfo& system_info,
+ nacl::NaClSandbox* nacl_sandbox,
PickleIterator* input_iter) {
Pickle write_pickle;
bool have_to_reply = false;
// Commands must write anything to send back to |write_pickle|.
switch (command_type) {
case nacl::kNaClForkRequest:
- have_to_reply = HandleForkRequest(attached_fds, system_info,
- input_iter, &write_pickle);
+ have_to_reply = HandleForkRequest(
+ attached_fds, system_info, nacl_sandbox, input_iter, &write_pickle);
break;
case nacl::kNaClGetTerminationStatusRequest:
have_to_reply =
@@ -324,14 +268,15 @@ bool HonorRequestAndReply(int reply_fd,
// Read a request from the Zygote from |zygote_ipc_fd| and handle it.
// Die on EOF from |zygote_ipc_fd|.
bool HandleZygoteRequest(int zygote_ipc_fd,
- const NaClLoaderSystemInfo& system_info) {
+ const NaClLoaderSystemInfo& system_info,
+ nacl::NaClSandbox* nacl_sandbox) {
std::vector<int> fds;
char buf[kNaClMaxIPCMessageLength];
const ssize_t msglen = UnixDomainSocket::RecvMsg(zygote_ipc_fd,
&buf, sizeof(buf), &fds);
// If the Zygote has started handling requests, we should be sandboxed via
// the setuid sandbox.
- if (!IsSandboxed()) {
+ if (!nacl_sandbox->layer_one_enabled()) {
LOG(ERROR) << "NaCl helper process running without a sandbox!\n"
<< "Most likely you need to configure your SUID sandbox "
<< "correctly";
@@ -352,8 +297,8 @@ bool HandleZygoteRequest(int zygote_ipc_fd,
LOG(ERROR) << "Unable to read command from Zygote";
return false;
}
- return HonorRequestAndReply(zygote_ipc_fd, command_type, fds, system_info,
- &read_iter);
+ return HonorRequestAndReply(
+ zygote_ipc_fd, command_type, fds, system_info, nacl_sandbox, &read_iter);
}
static const char kNaClHelperReservedAtZero[] = "reserved_at_zero";
@@ -470,13 +415,16 @@ int main(int argc, char* argv[]) {
CheckRDebug(argv[0]);
+ scoped_ptr<nacl::NaClSandbox> nacl_sandbox(new nacl::NaClSandbox);
// Make sure that the early initialization did not start any spurious
// threads.
#if !defined(THREAD_SANITIZER)
- CHECK(sandbox::ThreadHelpers::IsSingleThreaded(-1));
+ CHECK(nacl_sandbox->IsSingleThreaded());
#endif
- InitializeLayerOneSandbox();
+ const bool is_init_process = 1 == getpid();
+ nacl_sandbox->InitializeLayerOneSandbox();
+ CHECK_EQ(is_init_process, nacl_sandbox->layer_one_enabled());
const std::vector<int> empty;
// Send the zygote a message to let it know we are ready to help
@@ -488,8 +436,8 @@ int main(int argc, char* argv[]) {
// Now handle requests from the Zygote.
while (true) {
- bool request_handled = HandleZygoteRequest(kNaClZygoteDescriptor,
- system_info);
+ bool request_handled = HandleZygoteRequest(
+ kNaClZygoteDescriptor, system_info, nacl_sandbox.get());
// Do not turn this into a CHECK() without thinking about robustness
// against malicious IPC requests.
DCHECK(request_handled);
diff --git a/components/nacl/loader/nacl_sandbox_linux.h b/components/nacl/loader/nacl_sandbox_linux.h
deleted file mode 100644
index 8a61cb3..0000000
--- a/components/nacl/loader/nacl_sandbox_linux.h
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2013 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 COMPONENTS_NACL_LOADER_NACL_SANDBOX_LINUX_H_
-#define COMPONENTS_NACL_LOADER_NACL_SANDBOX_LINUX_H_
-
-bool InitializeBPFSandbox();
-
-#endif // COMPONENTS_NACL_LOADER_NACL_SANDBOX_LINUX_H_
diff --git a/components/nacl/loader/sandbox_linux/OWNERS b/components/nacl/loader/sandbox_linux/OWNERS
new file mode 100644
index 0000000..c25446f
--- /dev/null
+++ b/components/nacl/loader/sandbox_linux/OWNERS
@@ -0,0 +1,2 @@
+jln@chromium.org
+mseaborn@chromium.org
diff --git a/components/nacl/loader/nacl_sandbox_linux.cc b/components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.cc
index f1e4a49..e123523 100644
--- a/components/nacl/loader/nacl_sandbox_linux.cc
+++ b/components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/nacl/loader/nacl_sandbox_linux.h"
+#include "components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.h"
#include <errno.h>
#include <signal.h>
@@ -24,6 +24,8 @@ using sandbox::ErrorCode;
using sandbox::SandboxBPF;
using sandbox::SandboxBPFPolicy;
+namespace nacl {
+
namespace {
// On ARM and x86_64, System V shared memory calls have each their own system
@@ -172,3 +174,5 @@ bool InitializeBPFSandbox() {
#endif // defined(USE_SECCOMP_BPF)
return false;
}
+
+} // namespace nacl
diff --git a/components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.h b/components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.h
new file mode 100644
index 0000000..5bebd2a
--- /dev/null
+++ b/components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.h
@@ -0,0 +1,14 @@
+// Copyright 2013 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 COMPONENTS_NACL_LOADER_SANDBOX_LINUX_NACL_BPF_SANDBOX_LINUX_H_
+#define COMPONENTS_NACL_LOADER_SANDBOX_LINUX_NACL_BPF_SANDBOX_LINUX_H_
+
+namespace nacl {
+
+bool InitializeBPFSandbox();
+
+} // namespace nacl
+
+#endif // COMPONENTS_NACL_LOADER_SANDBOX_LINUX_NACL_BPF_SANDBOX_LINUX_H_
diff --git a/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc b/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc
new file mode 100644
index 0000000..1bf329d
--- /dev/null
+++ b/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc
@@ -0,0 +1,148 @@
+// Copyright 2014 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 "components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "build/build_config.h"
+#include "components/nacl/common/nacl_switches.h"
+#include "components/nacl/loader/nonsfi/nonsfi_sandbox.h"
+#include "components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.h"
+#include "sandbox/linux/services/credentials.h"
+#include "sandbox/linux/services/thread_helpers.h"
+#include "sandbox/linux/suid/client/setuid_sandbox_client.h"
+
+namespace nacl {
+
+namespace {
+
+// This is a poor man's check on whether we are sandboxed.
+bool IsSandboxed() {
+ int proc_fd = open("/proc/self/exe", O_RDONLY);
+ if (proc_fd >= 0) {
+ PCHECK(0 == IGNORE_EINTR(close(proc_fd)));
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+NaClSandbox::NaClSandbox()
+ : layer_one_enabled_(false),
+ layer_one_sealed_(false),
+ layer_two_enabled_(false),
+ layer_two_is_nonsfi_(false),
+ proc_fd_(-1) {
+ proc_fd_.reset(
+ HANDLE_EINTR(open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC)));
+ PCHECK(proc_fd_.is_valid());
+}
+
+NaClSandbox::~NaClSandbox() {
+}
+
+bool NaClSandbox::IsSingleThreaded() {
+ CHECK(proc_fd_.is_valid());
+ base::ScopedFD proc_self_task(HANDLE_EINTR(openat(
+ proc_fd_.get(), "self/task/", O_RDONLY | O_DIRECTORY | O_CLOEXEC)));
+ PCHECK(proc_self_task.is_valid());
+ return sandbox::ThreadHelpers::IsSingleThreaded(proc_self_task.get());
+}
+
+bool NaClSandbox::HasOpenDirectory() {
+ CHECK(proc_fd_.is_valid());
+ sandbox::Credentials credentials;
+ return credentials.HasOpenDirectory(proc_fd_.get());
+}
+
+void NaClSandbox::InitializeLayerOneSandbox() {
+ // Check that IsSandboxed() works. We should not be sandboxed at this point.
+ CHECK(!IsSandboxed()) << "Unexpectedly sandboxed!";
+ scoped_ptr<sandbox::SetuidSandboxClient> setuid_sandbox_client(
+ sandbox::SetuidSandboxClient::Create());
+ // Close the file descriptor that is an artefact of how the setuid sandbox
+ // works.
+ PCHECK(0 == IGNORE_EINTR(close(
+ setuid_sandbox_client->GetUniqueToChildFileDescriptor())));
+ const bool suid_sandbox_child = setuid_sandbox_client->IsSuidSandboxChild();
+
+ if (suid_sandbox_child) {
+ // Make sure that no directory file descriptor is open, as it would bypass
+ // the setuid sandbox model.
+ CHECK(!HasOpenDirectory());
+
+ // Get sandboxed.
+ CHECK(setuid_sandbox_client->ChrootMe());
+ CHECK(IsSandboxed());
+ layer_one_enabled_ = true;
+ }
+}
+
+void NaClSandbox::InitializeLayerTwoSandbox(bool uses_nonsfi_mode) {
+ // seccomp-bpf only applies to the current thread, so it's critical to only
+ // have a single thread running here.
+ DCHECK(!layer_one_sealed_);
+ CHECK(IsSingleThreaded());
+ if (uses_nonsfi_mode) {
+ layer_two_enabled_ = nacl::nonsfi::InitializeBPFSandbox();
+ layer_two_is_nonsfi_ = true;
+ } else {
+ layer_two_enabled_ = nacl::InitializeBPFSandbox();
+ }
+}
+
+void NaClSandbox::SealLayerOneSandbox() {
+ if (!layer_two_enabled_) {
+ // If nothing prevents us, check that there is no superfluous directory
+ // open.
+ CHECK(!HasOpenDirectory());
+ }
+ proc_fd_.reset();
+ layer_one_sealed_ = true;
+}
+
+void NaClSandbox::CheckSandboxingStateWithPolicy() {
+ static const char kItIsDangerousMsg[] = " this is dangerous.";
+ static const char kItIsNotAllowedMsg[] =
+ " this is not allowed in this configuration.";
+
+ const bool no_sandbox_for_nonsfi_ok =
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kNaClDangerousNoSandboxNonSfi);
+ const bool can_be_no_sandbox =
+ !layer_two_is_nonsfi_ || no_sandbox_for_nonsfi_ok;
+
+ if (!layer_one_enabled_ || !layer_one_sealed_) {
+ static const char kNoSuidMsg[] =
+ "The SUID sandbox is not engaged for NaCl:";
+ if (can_be_no_sandbox)
+ LOG(ERROR) << kNoSuidMsg << kItIsDangerousMsg;
+ else
+ LOG(FATAL) << kNoSuidMsg << kItIsNotAllowedMsg;
+ }
+
+ if (!layer_two_enabled_) {
+ static const char kNoBpfMsg[] =
+ "The seccomp-bpf sandbox is not engaged for NaCl:";
+ if (can_be_no_sandbox)
+ LOG(ERROR) << kNoBpfMsg << kItIsDangerousMsg;
+ else
+ LOG(FATAL) << kNoBpfMsg << kItIsNotAllowedMsg;
+ }
+}
+
+} // namespace nacl
diff --git a/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h b/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h
new file mode 100644
index 0000000..ab62625
--- /dev/null
+++ b/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h
@@ -0,0 +1,76 @@
+// Copyright 2014 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 COMPONENTS_NACL_LOADER_SANDBOX_LINUX_NACL_SANDBOX_LINUX_H_
+#define COMPONENTS_NACL_LOADER_SANDBOX_LINUX_NACL_SANDBOX_LINUX_H_
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+
+namespace nacl {
+
+// NaClSandbox supports two independent layers of sandboxing.
+// layer-1 uses a chroot. It requires both InitializeLayerOneSandbox() and
+// SealLayerOneSandbox() to have been called to be enforcing.
+// layer-2 uses seccomp-bpf. It requires the layer-1 sandbox to not yet be
+// sealed when being engaged.
+// For the layer-1 sandbox to work, the current process must be a child of
+// the setuid sandbox. InitializeLayerOneSandbox() can only be called once
+// per instance of the setuid sandbox.
+//
+// A typical use case of this class would be:
+// 1. Load libraries and do some pre-initialization
+// 2. InitializeLayerOneSandbox();
+// 3. Do some more initializations (it is ok to fork() here).
+// 4. CHECK(!HasOpenDirectory));
+// (This check is not strictly necessary, as the only possibility for a
+// new directory descriptor to exist after (2) has been called is via IPC)).
+// 5. InitializeLayerTwoSandbox();
+// 6. SealLayerOneSandbox();
+// 7. CheckSandboxingStateWithPolicy();
+class NaClSandbox {
+ public:
+ NaClSandbox();
+ ~NaClSandbox();
+
+ // This API will only work if the layer-1 sandbox is not sealed and the
+ // layer-2 sandbox is not engaged.
+ bool IsSingleThreaded();
+ // Check whether the current process owns any directory file descriptors. This
+ // will ignore any directory file descriptor owned by this object (i.e. those
+ // that will be closed after SealLayerOneSandbox()) is called.
+ // This API will only work if the layer-1 sandbox is not sealed and the
+ // layer-2 sandbox is not engaged.
+ bool HasOpenDirectory();
+ // Will attempt to initialize the layer-1 sandbox, depending on flags and the
+ // environment. It can only succeed if the current process is a child of the
+ // setuid sandbox.
+ void InitializeLayerOneSandbox();
+ // Will attempt to initialize the layer-2 sandbox, depending on flags and the
+ // environment. |uses_nonsfi_mode| describes which seccomp-bpf policy is
+ // appropriate.
+ void InitializeLayerTwoSandbox(bool uses_nonsfi_mode);
+ // Seal the layer-1 sandbox, making it enforcing.
+ void SealLayerOneSandbox();
+ // Check that the current sandboxing state matches the level of sandboxing
+ // expected for NaCl in the current configuration. Crash if it does not.
+ void CheckSandboxingStateWithPolicy();
+
+ bool layer_one_enabled() { return layer_one_enabled_; }
+ bool layer_two_enabled() { return layer_two_enabled_; }
+
+ private:
+ bool layer_one_enabled_;
+ bool layer_one_sealed_;
+ bool layer_two_enabled_;
+ bool layer_two_is_nonsfi_;
+ // |proc_fd_| must be released before the layer-1 sandbox is considered
+ // enforcing.
+ base::ScopedFD proc_fd_;
+ DISALLOW_COPY_AND_ASSIGN(NaClSandbox);
+};
+
+} // namespace nacl
+
+#endif // COMPONENTS_NACL_LOADER_SANDBOX_LINUX_NACL_SANDBOX_LINUX_H_