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"
11 #include <sys/types.h>
16 #include "base/basictypes.h"
17 #include "base/callback.h"
18 #include "base/command_line.h"
19 #include "base/compiler_specific.h"
20 #include "base/files/scoped_file.h"
21 #include "base/logging.h"
22 #include "base/memory/scoped_ptr.h"
23 #include "base/posix/eintr_wrapper.h"
24 #include "build/build_config.h"
25 #include "components/nacl/common/nacl_switches.h"
26 #include "components/nacl/loader/nonsfi/nonsfi_sandbox.h"
27 #include "components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.h"
28 #include "content/public/common/content_switches.h"
29 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
30 #include "sandbox/linux/services/credentials.h"
31 #include "sandbox/linux/services/namespace_sandbox.h"
32 #include "sandbox/linux/services/proc_util.h"
33 #include "sandbox/linux/services/resource_limits.h"
34 #include "sandbox/linux/services/thread_helpers.h"
35 #include "sandbox/linux/suid/client/setuid_sandbox_client.h"
41 // This is a poor man's check on whether we are sandboxed.
43 int proc_fd
= open("/proc/self/exe", O_RDONLY
);
45 PCHECK(0 == IGNORE_EINTR(close(proc_fd
)));
51 bool MaybeSetProcessNonDumpable() {
52 const base::CommandLine
& command_line
=
53 *base::CommandLine::ForCurrentProcess();
54 if (command_line
.HasSwitch(switches::kAllowSandboxDebugging
)) {
58 if (prctl(PR_SET_DUMPABLE
, 0, 0, 0, 0) != 0) {
59 PLOG(ERROR
) << "Failed to set non-dumpable flag";
63 return prctl(PR_GET_DUMPABLE
) == 0;
66 void RestrictAddressSpaceUsage() {
67 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
68 defined(THREAD_SANITIZER)
69 // Sanitizers need to reserve huge chunks of the address space.
73 // Add a limit to the brk() heap that would prevent allocations that can't be
74 // indexed by an int. This helps working around typical security bugs.
75 // This could almost certainly be set to zero. GLibc's allocator and others
76 // would fall-back to mmap if brk() fails.
77 const rlim_t kNewDataSegmentMaxSize
= std::numeric_limits
<int>::max();
78 CHECK(sandbox::ResourceLimits::Lower(RLIMIT_DATA
, kNewDataSegmentMaxSize
));
80 #if defined(ARCH_CPU_64_BITS)
81 // NaCl's x86-64 sandbox allocated 88GB address of space during startup:
82 // - The main sandbox is 4GB
83 // - There are two guard regions of 40GB each.
84 // - 4GB are allocated extra to have a 4GB-aligned address.
85 // See https://crbug.com/455839
87 // Set the limit to 128 GB and have some margin.
88 const rlim_t kNewAddressSpaceLimit
= 1UL << 37;
90 // Some architectures such as X86 allow 32 bits processes to switch to 64
91 // bits when running under 64 bits kernels. Set a limit in case this happens.
92 const rlim_t kNewAddressSpaceLimit
= std::numeric_limits
<uint32_t>::max();
94 CHECK(sandbox::ResourceLimits::Lower(RLIMIT_AS
, kNewAddressSpaceLimit
));
99 NaClSandbox::NaClSandbox()
100 : layer_one_enabled_(false),
101 layer_one_sealed_(false),
102 layer_two_enabled_(false),
103 layer_two_is_nonsfi_(false),
105 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) {
107 HANDLE_EINTR(open("/proc", O_DIRECTORY
| O_RDONLY
| O_CLOEXEC
)));
108 PCHECK(proc_fd_
.is_valid());
111 NaClSandbox::~NaClSandbox() {
114 bool NaClSandbox::IsSingleThreaded() {
115 CHECK(proc_fd_
.is_valid());
116 return sandbox::ThreadHelpers::IsSingleThreaded(proc_fd_
.get());
119 bool NaClSandbox::HasOpenDirectory() {
120 CHECK(proc_fd_
.is_valid());
121 return sandbox::ProcUtil::HasOpenDirectory(proc_fd_
.get());
124 void NaClSandbox::InitializeLayerOneSandbox() {
125 // Check that IsSandboxed() works. We should not be sandboxed at this point.
126 CHECK(!IsSandboxed()) << "Unexpectedly sandboxed!";
128 if (setuid_sandbox_client_
->IsSuidSandboxChild()) {
129 setuid_sandbox_client_
->CloseDummyFile();
131 // Make sure that no directory file descriptor is open, as it would bypass
132 // the setuid sandbox model.
133 CHECK(!HasOpenDirectory());
136 CHECK(setuid_sandbox_client_
->ChrootMe());
137 CHECK(MaybeSetProcessNonDumpable());
138 CHECK(IsSandboxed());
139 layer_one_enabled_
= true;
140 } else if (sandbox::NamespaceSandbox::InNewUserNamespace()) {
141 CHECK(sandbox::Credentials::MoveToNewUserNS());
142 CHECK(sandbox::Credentials::DropFileSystemAccess(proc_fd_
.get()));
144 // We do not drop CAP_SYS_ADMIN because we need it to place each child
145 // process in its own PID namespace later on.
146 std::vector
<sandbox::Credentials::Capability
> caps
;
147 caps
.push_back(sandbox::Credentials::Capability::SYS_ADMIN
);
148 CHECK(sandbox::Credentials::SetCapabilities(proc_fd_
.get(), caps
));
150 CHECK(IsSandboxed());
151 layer_one_enabled_
= true;
155 void NaClSandbox::CheckForExpectedNumberOfOpenFds() {
156 // We expect to have the following FDs open:
157 // 1-3) stdin, stdout, stderr.
158 // 4) The /dev/urandom FD used by base::GetUrandomFD().
159 // 5) A dummy pipe FD used to overwrite kSandboxIPCChannel.
160 // 6) The socket for the Chrome IPC channel that's connected to the
161 // browser process, kPrimaryIPCChannel.
162 // We also have an fd for /proc (proc_fd_), but CountOpenFds excludes this.
164 // This sanity check ensures that dynamically loaded libraries don't
165 // leave any FDs open before we enable the sandbox.
166 int expected_num_fds
= 6;
167 if (setuid_sandbox_client_
->IsSuidSandboxChild()) {
168 // When using the setuid sandbox, there is one additional socket used for
169 // ChrootMe(). After ChrootMe(), it is no longer connected to anything.
173 CHECK_EQ(expected_num_fds
, sandbox::ProcUtil::CountOpenFds(proc_fd_
.get()));
176 void NaClSandbox::InitializeLayerTwoSandbox(bool uses_nonsfi_mode
) {
177 // seccomp-bpf only applies to the current thread, so it's critical to only
178 // have a single thread running here.
179 DCHECK(!layer_one_sealed_
);
180 CHECK(IsSingleThreaded());
181 CheckForExpectedNumberOfOpenFds();
183 RestrictAddressSpaceUsage();
185 // Pass proc_fd_ ownership to the BPF sandbox, which guarantees it will
186 // be closed. There is no point in keeping it around since the BPF policy
187 // will prevent its usage.
188 if (uses_nonsfi_mode
) {
189 layer_two_enabled_
= nacl::nonsfi::InitializeBPFSandbox(proc_fd_
.Pass());
190 layer_two_is_nonsfi_
= true;
192 #if defined(OS_NACL_NONSFI)
193 LOG(FATAL
) << "nacl_helper_nonsfi can run only Non-SFI plugin.";
195 layer_two_enabled_
= nacl::InitializeBPFSandbox(proc_fd_
.Pass());
200 void NaClSandbox::SealLayerOneSandbox() {
201 if (proc_fd_
.is_valid() && !layer_two_enabled_
) {
202 // If nothing prevents us, check that there is no superfluous directory
204 CHECK(!HasOpenDirectory());
207 layer_one_sealed_
= true;
210 void NaClSandbox::CheckSandboxingStateWithPolicy() {
211 static const char kItIsDangerousMsg
[] = " this is dangerous.";
212 static const char kItIsNotAllowedMsg
[] =
213 " this is not allowed in this configuration.";
215 const bool no_sandbox_for_nonsfi_ok
=
216 #if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
217 defined(MEMORY_SANITIZER) || defined(LEAK_SANITIZER)
218 // Sanitizer tests run with --no-sandbox, but without
219 // --nacl-dangerous-no-sandbox-nonsfi. Allow that case.
222 base::CommandLine::ForCurrentProcess()->HasSwitch(
223 switches::kNaClDangerousNoSandboxNonSfi
);
226 const bool can_be_no_sandbox
=
227 !layer_two_is_nonsfi_
|| no_sandbox_for_nonsfi_ok
;
229 if (!layer_one_enabled_
|| !layer_one_sealed_
) {
230 static const char kNoSuidMsg
[] =
231 "The SUID sandbox is not engaged for NaCl:";
232 if (can_be_no_sandbox
)
233 LOG(ERROR
) << kNoSuidMsg
<< kItIsDangerousMsg
;
235 LOG(FATAL
) << kNoSuidMsg
<< kItIsNotAllowedMsg
;
238 if (!layer_two_enabled_
) {
239 static const char kNoBpfMsg
[] =
240 "The seccomp-bpf sandbox is not engaged for NaCl:";
241 if (can_be_no_sandbox
)
242 LOG(ERROR
) << kNoBpfMsg
<< kItIsDangerousMsg
;
244 LOG(FATAL
) << kNoBpfMsg
<< kItIsNotAllowedMsg
;