Delete chrome.mediaGalleriesPrivate because the functionality unique to it has since...
[chromium-blink-merge.git] / components / nacl / loader / sandbox_linux / nacl_sandbox_linux.cc
blob5c4fa4224f7c2d0efbb4d203911da1286cb40fbb
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h"
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <unistd.h>
13 #include "base/basictypes.h"
14 #include "base/callback.h"
15 #include "base/command_line.h"
16 #include "base/compiler_specific.h"
17 #include "base/files/scoped_file.h"
18 #include "base/logging.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "base/posix/eintr_wrapper.h"
21 #include "build/build_config.h"
22 #include "components/nacl/common/nacl_switches.h"
23 #include "components/nacl/loader/nonsfi/nonsfi_sandbox.h"
24 #include "components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.h"
25 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
26 #include "sandbox/linux/services/proc_util.h"
27 #include "sandbox/linux/services/thread_helpers.h"
28 #include "sandbox/linux/suid/client/setuid_sandbox_client.h"
30 namespace nacl {
32 namespace {
34 // This is a poor man's check on whether we are sandboxed.
35 bool IsSandboxed() {
36 int proc_fd = open("/proc/self/exe", O_RDONLY);
37 if (proc_fd >= 0) {
38 PCHECK(0 == IGNORE_EINTR(close(proc_fd)));
39 return false;
41 return true;
44 // Open a new file descriptor to /proc/self/task/ by using
45 // |proc_fd|.
46 base::ScopedFD GetProcSelfTask(int proc_fd) {
47 base::ScopedFD proc_self_task(HANDLE_EINTR(
48 openat(proc_fd, "self/task/", O_RDONLY | O_DIRECTORY | O_CLOEXEC)));
49 PCHECK(proc_self_task.is_valid());
50 return proc_self_task.Pass();
53 } // namespace
55 NaClSandbox::NaClSandbox()
56 : layer_one_enabled_(false),
57 layer_one_sealed_(false),
58 layer_two_enabled_(false),
59 layer_two_is_nonsfi_(false),
60 proc_fd_(-1),
61 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) {
62 proc_fd_.reset(
63 HANDLE_EINTR(open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC)));
64 PCHECK(proc_fd_.is_valid());
67 NaClSandbox::~NaClSandbox() {
70 bool NaClSandbox::IsSingleThreaded() {
71 CHECK(proc_fd_.is_valid());
72 base::ScopedFD proc_self_task(GetProcSelfTask(proc_fd_.get()));
73 return sandbox::ThreadHelpers::IsSingleThreaded(proc_self_task.get());
76 bool NaClSandbox::HasOpenDirectory() {
77 CHECK(proc_fd_.is_valid());
78 return sandbox::ProcUtil::HasOpenDirectory(proc_fd_.get());
81 void NaClSandbox::InitializeLayerOneSandbox() {
82 // Check that IsSandboxed() works. We should not be sandboxed at this point.
83 CHECK(!IsSandboxed()) << "Unexpectedly sandboxed!";
85 if (setuid_sandbox_client_->IsSuidSandboxChild()) {
86 setuid_sandbox_client_->CloseDummyFile();
88 // Make sure that no directory file descriptor is open, as it would bypass
89 // the setuid sandbox model.
90 CHECK(!HasOpenDirectory());
92 // Get sandboxed.
93 CHECK(setuid_sandbox_client_->ChrootMe());
94 CHECK(IsSandboxed());
95 layer_one_enabled_ = true;
99 void NaClSandbox::CheckForExpectedNumberOfOpenFds() {
100 if (setuid_sandbox_client_->IsSuidSandboxChild()) {
101 // We expect to have the following FDs open:
102 // 1-3) stdin, stdout, stderr.
103 // 4) The /dev/urandom FD used by base::GetUrandomFD().
104 // 5) A dummy pipe FD used to overwrite kSandboxIPCChannel.
105 // 6) The socket created by the SUID sandbox helper, used by ChrootMe().
106 // After ChrootMe(), this is no longer connected to anything.
107 // (Only present when running under the SUID sandbox.)
108 // 7) The socket for the Chrome IPC channel that's connected to the
109 // browser process, kPrimaryIPCChannel.
111 // This sanity check ensures that dynamically loaded libraries don't
112 // leave any FDs open before we enable the sandbox.
113 CHECK_EQ(7, sandbox::ProcUtil::CountOpenFds(proc_fd_.get()));
117 void NaClSandbox::InitializeLayerTwoSandbox(bool uses_nonsfi_mode) {
118 // seccomp-bpf only applies to the current thread, so it's critical to only
119 // have a single thread running here.
120 DCHECK(!layer_one_sealed_);
121 CHECK(IsSingleThreaded());
122 CheckForExpectedNumberOfOpenFds();
124 base::ScopedFD proc_self_task(GetProcSelfTask(proc_fd_.get()));
126 if (uses_nonsfi_mode) {
127 layer_two_enabled_ =
128 nacl::nonsfi::InitializeBPFSandbox(proc_self_task.Pass());
129 layer_two_is_nonsfi_ = true;
130 } else {
131 layer_two_enabled_ = nacl::InitializeBPFSandbox(proc_self_task.Pass());
135 void NaClSandbox::SealLayerOneSandbox() {
136 if (!layer_two_enabled_) {
137 // If nothing prevents us, check that there is no superfluous directory
138 // open.
139 CHECK(!HasOpenDirectory());
141 proc_fd_.reset();
142 layer_one_sealed_ = true;
145 void NaClSandbox::CheckSandboxingStateWithPolicy() {
146 static const char kItIsDangerousMsg[] = " this is dangerous.";
147 static const char kItIsNotAllowedMsg[] =
148 " this is not allowed in this configuration.";
150 const bool no_sandbox_for_nonsfi_ok =
151 base::CommandLine::ForCurrentProcess()->HasSwitch(
152 switches::kNaClDangerousNoSandboxNonSfi);
153 const bool can_be_no_sandbox =
154 !layer_two_is_nonsfi_ || no_sandbox_for_nonsfi_ok;
156 if (!layer_one_enabled_ || !layer_one_sealed_) {
157 static const char kNoSuidMsg[] =
158 "The SUID sandbox is not engaged for NaCl:";
159 if (can_be_no_sandbox)
160 LOG(ERROR) << kNoSuidMsg << kItIsDangerousMsg;
161 else
162 LOG(FATAL) << kNoSuidMsg << kItIsNotAllowedMsg;
165 if (!layer_two_enabled_) {
166 static const char kNoBpfMsg[] =
167 "The seccomp-bpf sandbox is not engaged for NaCl:";
168 if (can_be_no_sandbox)
169 LOG(ERROR) << kNoBpfMsg << kItIsDangerousMsg;
170 else
171 LOG(FATAL) << kNoBpfMsg << kItIsNotAllowedMsg;
175 } // namespace nacl