Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(231)

Unified Diff: components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc

Issue 250773003: NaCl Linux: create NaClSandbox class (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Minor namespace cleanup. Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc
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 0000000000000000000000000000000000000000..76572de90d151e2c2e480e7a8cbaf343dca06ff7
--- /dev/null
+++ b/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc
@@ -0,0 +1,146 @@
+// 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_non_sfi_(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_non_sfi_ = 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[] = " it is dangerous.";
Mark Seaborn 2014/04/29 00:28:22 How about "this is dangerous", otherwise it seems
jln (very slow on Chromium) 2014/04/29 01:28:32 Done.
+ static const char kItIsNotAllowedMsg[] =
+ " this is not allowed in this configuration.";
+
+ const bool no_sandbox_for_non_sfi_ok =
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kNaClDangerousNoSandboxNonSfi);
+ const bool can_be_no_sandbox =
+ !layer_two_is_non_sfi_ || no_sandbox_for_non_sfi_ok;
+
+ if (!layer_one_enabled_ || !layer_one_sealed_) {
+ static const char kNoSuidMsg[] = "The SUID sandbox is not engaged,";
Mark Seaborn 2014/04/29 00:28:22 Nit: comma splice, use ":" or ";" instead of ",".
jln (very slow on Chromium) 2014/04/29 01:28:32 Done.
+ 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,";
+ if (can_be_no_sandbox)
+ LOG(ERROR) << kNoBpfMsg << kItIsDangerousMsg;
+ else
+ LOG(FATAL) << kNoBpfMsg << kItIsNotAllowedMsg;
+ }
+}
+
+} // namespace nacl

Powered by Google App Engine
This is Rietveld 408576698