OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/nacl/loader/nonsfi/nonsfi_sandbox.h" | 5 #include "components/nacl/loader/nonsfi/nonsfi_sandbox.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <linux/net.h> | 9 #include <linux/net.h> |
10 #include <sys/mman.h> | 10 #include <sys/mman.h> |
11 #include <sys/prctl.h> | 11 #include <sys/prctl.h> |
12 #include <sys/socket.h> | 12 #include <sys/socket.h> |
13 #include <sys/syscall.h> | 13 #include <sys/syscall.h> |
14 #include <sys/time.h> | 14 #include <sys/time.h> |
15 | 15 |
16 #include "base/basictypes.h" | 16 #include "base/basictypes.h" |
17 #include "base/logging.h" | 17 #include "base/logging.h" |
18 #include "base/time/time.h" | 18 #include "base/time/time.h" |
19 #include "build/build_config.h" | 19 #include "build/build_config.h" |
20 #include "content/public/common/sandbox_init.h" | 20 #include "content/public/common/sandbox_init.h" |
21 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" | 21 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" |
22 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" | 22 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" |
23 #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h" | 23 #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h" |
24 #include "sandbox/linux/system_headers/linux_futex.h" | 24 #include "sandbox/linux/system_headers/linux_futex.h" |
| 25 #include "sandbox/linux/system_headers/linux_signal.h" |
25 #include "sandbox/linux/system_headers/linux_syscalls.h" | 26 #include "sandbox/linux/system_headers/linux_syscalls.h" |
26 | 27 |
27 // Chrome OS Daisy (ARM) build environment and PNaCl toolchain do not define | 28 // Chrome OS Daisy (ARM) build environment and PNaCl toolchain do not define |
28 // MAP_STACK. | 29 // MAP_STACK. |
29 #if !defined(MAP_STACK) | 30 #if !defined(MAP_STACK) |
30 # if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) | 31 # if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) |
31 # define MAP_STACK 0x20000 | 32 # define MAP_STACK 0x20000 |
32 # else | 33 # else |
33 // Note that, on other architecture, MAP_STACK has different value (e.g. mips' | 34 // Note that, on other architecture, MAP_STACK has different value (e.g. mips' |
34 // MAP_STACK is 0x40000), though Non-SFI is not supported on such | 35 // MAP_STACK is 0x40000), though Non-SFI is not supported on such |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 | 77 |
77 ResultExpr RestrictClone() { | 78 ResultExpr RestrictClone() { |
78 // We allow clone only for new thread creation. | 79 // We allow clone only for new thread creation. |
79 int clone_flags = | 80 int clone_flags = |
80 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | | 81 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | |
81 CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS; | 82 CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS; |
82 #if !defined(OS_NACL_NONSFI) | 83 #if !defined(OS_NACL_NONSFI) |
83 clone_flags |= CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; | 84 clone_flags |= CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; |
84 #endif | 85 #endif |
85 const Arg<int> flags(0); | 86 const Arg<int> flags(0); |
86 return If(flags == clone_flags, Allow()).Else(CrashSIGSYSClone()); | 87 // TODO(lhchavez): Add CLONE_PARENT_SETTID unconditionally to the allowed |
| 88 // flags after the NaCl roll. |
| 89 return If(flags == clone_flags || |
| 90 flags == (clone_flags | CLONE_PARENT_SETTID), |
| 91 Allow()).Else(CrashSIGSYSClone()); |
87 } | 92 } |
88 | 93 |
89 ResultExpr RestrictFutexOperation() { | 94 ResultExpr RestrictFutexOperation() { |
90 // TODO(hamaji): Allow only FUTEX_PRIVATE_FLAG futexes. | 95 // TODO(hamaji): Allow only FUTEX_PRIVATE_FLAG futexes. |
91 const uint64_t kAllowedFutexFlags = FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME; | 96 const uint64_t kAllowedFutexFlags = FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME; |
92 const Arg<int> op(1); | 97 const Arg<int> op(1); |
93 return Switch(op & ~kAllowedFutexFlags) | 98 return Switch(op & ~kAllowedFutexFlags) |
94 .CASES((FUTEX_WAIT, | 99 .CASES((FUTEX_WAIT, |
95 FUTEX_WAKE, | 100 FUTEX_WAKE, |
96 FUTEX_REQUEUE, | 101 FUTEX_REQUEUE, |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_FIXED; | 144 MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_FIXED; |
140 // When PROT_EXEC is specified, IRT mmap of Non-SFI NaCl helper | 145 // When PROT_EXEC is specified, IRT mmap of Non-SFI NaCl helper |
141 // calls mmap without PROT_EXEC and then adds PROT_EXEC by mprotect, | 146 // calls mmap without PROT_EXEC and then adds PROT_EXEC by mprotect, |
142 // so we do not need to allow PROT_EXEC in mmap. | 147 // so we do not need to allow PROT_EXEC in mmap. |
143 const uint64_t kAllowedProtMask = PROT_READ | PROT_WRITE; | 148 const uint64_t kAllowedProtMask = PROT_READ | PROT_WRITE; |
144 const Arg<int> prot(2), flags(3); | 149 const Arg<int> prot(2), flags(3); |
145 return If((prot & ~kAllowedProtMask) == 0 && (flags & ~kAllowedFlagMask) == 0, | 150 return If((prot & ~kAllowedProtMask) == 0 && (flags & ~kAllowedFlagMask) == 0, |
146 Allow()).Else(CrashSIGSYS()); | 151 Allow()).Else(CrashSIGSYS()); |
147 } | 152 } |
148 | 153 |
| 154 ResultExpr RestrictTgkill(int policy_pid) { |
| 155 const Arg<int> tgid(0), tid(1), signum(2); |
| 156 // Only sending SIGUSR1 to a thread in the same process is allowed. |
| 157 return If(tgid == policy_pid && |
| 158 // Arg does not support a greater-than operator, so two separate |
| 159 // checks are needed to ensure tid is positive. |
| 160 tid != 0 && |
| 161 (tid & (1u << 31)) == 0 && // tid is non-negative. |
| 162 signum == LINUX_SIGUSR1, |
| 163 Allow()).Else(CrashSIGSYS()); |
| 164 } |
| 165 |
149 #if !defined(OS_NACL_NONSFI) && (defined(__x86_64__) || defined(__arm__)) | 166 #if !defined(OS_NACL_NONSFI) && (defined(__x86_64__) || defined(__arm__)) |
150 ResultExpr RestrictSocketpair() { | 167 ResultExpr RestrictSocketpair() { |
151 // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen. | 168 // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen. |
152 static_assert(AF_UNIX == PF_UNIX, "AF_UNIX must equal PF_UNIX."); | 169 static_assert(AF_UNIX == PF_UNIX, "AF_UNIX must equal PF_UNIX."); |
153 const Arg<int> domain(0); | 170 const Arg<int> domain(0); |
154 return If(domain == AF_UNIX, Allow()).Else(CrashSIGSYS()); | 171 return If(domain == AF_UNIX, Allow()).Else(CrashSIGSYS()); |
155 } | 172 } |
156 #endif | 173 #endif |
157 | 174 |
158 bool IsGracefullyDenied(int sysno) { | 175 bool IsGracefullyDenied(int sysno) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 // Make a ptrace request with an invalid PID. | 221 // Make a ptrace request with an invalid PID. |
205 long ptrace_ret = syscall( | 222 long ptrace_ret = syscall( |
206 __NR_ptrace, 3 /* = PTRACE_PEEKUSER */, -1 /* pid */, NULL, NULL); | 223 __NR_ptrace, 3 /* = PTRACE_PEEKUSER */, -1 /* pid */, NULL, NULL); |
207 CHECK_EQ(-1, ptrace_ret); | 224 CHECK_EQ(-1, ptrace_ret); |
208 // Without the sandbox on, this ptrace call would ESRCH instead. | 225 // Without the sandbox on, this ptrace call would ESRCH instead. |
209 CHECK_EQ(EPERM, errno); | 226 CHECK_EQ(EPERM, errno); |
210 } | 227 } |
211 | 228 |
212 } // namespace | 229 } // namespace |
213 | 230 |
| 231 NaClNonSfiBPFSandboxPolicy::NaClNonSfiBPFSandboxPolicy() |
| 232 : policy_pid_(getpid()) { |
| 233 } |
| 234 |
| 235 NaClNonSfiBPFSandboxPolicy::~NaClNonSfiBPFSandboxPolicy() { |
| 236 // Make sure that this policy is created, used and destroyed by a single |
| 237 // process. |
| 238 DCHECK_EQ(getpid(), policy_pid_); |
| 239 } |
| 240 |
214 ResultExpr NaClNonSfiBPFSandboxPolicy::EvaluateSyscall(int sysno) const { | 241 ResultExpr NaClNonSfiBPFSandboxPolicy::EvaluateSyscall(int sysno) const { |
215 switch (sysno) { | 242 switch (sysno) { |
216 // Allowed syscalls. | 243 // Allowed syscalls. |
217 #if defined(__i386__) || defined(__arm__) | 244 #if defined(__i386__) || defined(__arm__) |
218 case __NR__llseek: | 245 case __NR__llseek: |
219 #elif defined(__x86_64__) | 246 #elif defined(__x86_64__) |
220 case __NR_lseek: | 247 case __NR_lseek: |
221 #endif | 248 #endif |
222 case __NR_close: | 249 case __NR_close: |
223 case __NR_dup: | 250 case __NR_dup: |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 #if !defined(OS_NACL_NONSFI) | 324 #if !defined(OS_NACL_NONSFI) |
298 // nacl_helper in Non-SFI mode still uses socketpair() internally | 325 // nacl_helper in Non-SFI mode still uses socketpair() internally |
299 // via libevent. | 326 // via libevent. |
300 // TODO(hidehiko): Remove this when the switching to nacl_helper_nonsfi | 327 // TODO(hidehiko): Remove this when the switching to nacl_helper_nonsfi |
301 // is completed. | 328 // is completed. |
302 case __NR_socketpair: | 329 case __NR_socketpair: |
303 return RestrictSocketpair(); | 330 return RestrictSocketpair(); |
304 #endif | 331 #endif |
305 #endif | 332 #endif |
306 | 333 |
| 334 case __NR_tgkill: |
| 335 return RestrictTgkill(policy_pid_); |
| 336 |
307 case __NR_brk: | 337 case __NR_brk: |
308 // The behavior of brk on Linux is different from other system | 338 // The behavior of brk on Linux is different from other system |
309 // calls. It does not return errno but the current break on | 339 // calls. It does not return errno but the current break on |
310 // failure. glibc thinks brk failed if the return value of brk | 340 // failure. glibc thinks brk failed if the return value of brk |
311 // is less than the requested address (i.e., brk(addr) < addr). | 341 // is less than the requested address (i.e., brk(addr) < addr). |
312 // So, glibc thinks brk succeeded if we return -EPERM and we | 342 // So, glibc thinks brk succeeded if we return -EPERM and we |
313 // need to return zero instead. | 343 // need to return zero instead. |
314 return Error(0); | 344 return Error(0); |
315 | 345 |
316 default: | 346 default: |
(...skipping 13 matching lines...) Expand all Loading... |
330 new nacl::nonsfi::NaClNonSfiBPFSandboxPolicy()), | 360 new nacl::nonsfi::NaClNonSfiBPFSandboxPolicy()), |
331 proc_fd.Pass()); | 361 proc_fd.Pass()); |
332 if (!sandbox_is_initialized) | 362 if (!sandbox_is_initialized) |
333 return false; | 363 return false; |
334 RunSandboxSanityChecks(); | 364 RunSandboxSanityChecks(); |
335 return true; | 365 return true; |
336 } | 366 } |
337 | 367 |
338 } // namespace nonsfi | 368 } // namespace nonsfi |
339 } // namespace nacl | 369 } // namespace nacl |
OLD | NEW |