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/prctl.h> | 10 #include <sys/prctl.h> |
11 #include <sys/ptrace.h> | 11 #include <sys/ptrace.h> |
12 #include <sys/mman.h> | 12 #include <sys/mman.h> |
13 #include <sys/socket.h> | 13 #include <sys/socket.h> |
14 #include <sys/syscall.h> | 14 #include <sys/syscall.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 "build/build_config.h" | 18 #include "build/build_config.h" |
19 #include "content/public/common/sandbox_init.h" | 19 #include "content/public/common/sandbox_init.h" |
| 20 #include "sandbox/linux/seccomp-bpf-helpers/bpf_dsl.h" |
20 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" | 21 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" |
21 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 22 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
22 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" | 23 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" |
23 #include "sandbox/linux/seccomp-bpf/trap.h" | |
24 #include "sandbox/linux/services/linux_syscalls.h" | 24 #include "sandbox/linux/services/linux_syscalls.h" |
25 | 25 |
26 #if defined(__arm__) && !defined(MAP_STACK) | 26 #if defined(__arm__) && !defined(MAP_STACK) |
27 // Chrome OS Daisy (ARM) build environment has old headers. | 27 // Chrome OS Daisy (ARM) build environment has old headers. |
28 #define MAP_STACK 0x20000 | 28 #define MAP_STACK 0x20000 |
29 #endif | 29 #endif |
30 | 30 |
31 using sandbox::ErrorCode; | 31 using namespace sandbox::bpf_dsl; |
32 using sandbox::SandboxBPF; | |
33 | 32 |
34 namespace nacl { | 33 namespace nacl { |
35 namespace nonsfi { | 34 namespace nonsfi { |
36 namespace { | 35 namespace { |
37 | 36 |
38 ErrorCode RestrictFcntlCommands(SandboxBPF* sb) { | 37 ResultExpr RestrictFcntlCommands() { |
39 ErrorCode::ArgType mask_long_type; | |
40 if (sizeof(long) == 8) { | |
41 mask_long_type = ErrorCode::TP_64BIT; | |
42 } else if (sizeof(long) == 4) { | |
43 mask_long_type = ErrorCode::TP_32BIT; | |
44 } else { | |
45 NOTREACHED(); | |
46 } | |
47 // We allow following cases: | 38 // We allow following cases: |
48 // 1. F_SETFD + FD_CLOEXEC: libevent's epoll_init uses this. | 39 // 1. F_SETFD + FD_CLOEXEC: libevent's epoll_init uses this. |
49 // 2. F_GETFL: Used by SetNonBlocking in | 40 // 2. F_GETFL: Used by SetNonBlocking in |
50 // message_pump_libevent.cc and Channel::ChannelImpl::CreatePipe | 41 // message_pump_libevent.cc and Channel::ChannelImpl::CreatePipe |
51 // in ipc_channel_posix.cc. Note that the latter does not work | 42 // in ipc_channel_posix.cc. Note that the latter does not work |
52 // with EPERM. | 43 // with EPERM. |
53 // 3. F_SETFL: Used by evutil_make_socket_nonblocking in | 44 // 3. F_SETFL: Used by evutil_make_socket_nonblocking in |
54 // libevent and SetNonBlocking. As the latter mix O_NONBLOCK to | 45 // libevent and SetNonBlocking. As the latter mix O_NONBLOCK to |
55 // the return value of F_GETFL, so we need to allow O_ACCMODE in | 46 // the return value of F_GETFL, so we need to allow O_ACCMODE in |
56 // addition to O_NONBLOCK. | 47 // addition to O_NONBLOCK. |
57 const unsigned long denied_mask = ~(O_ACCMODE | O_NONBLOCK); | 48 const unsigned long denied_mask = ~(O_ACCMODE | O_NONBLOCK); |
58 return sb->Cond(1, ErrorCode::TP_32BIT, | 49 const Arg<int> cmd_arg(1); |
59 ErrorCode::OP_EQUAL, F_SETFD, | 50 const Arg<unsigned long> extra_arg(2); |
60 sb->Cond(2, mask_long_type, | 51 return If((cmd_arg == F_SETFD && extra_arg == FD_CLOEXEC) || |
61 ErrorCode::OP_EQUAL, FD_CLOEXEC, | 52 (cmd_arg == F_GETFL) || |
62 ErrorCode(ErrorCode::ERR_ALLOWED), | 53 (cmd_arg == F_SETFL && (extra_arg & denied_mask) == 0)).Then( |
63 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL)), | 54 Allow() |
64 sb->Cond(1, ErrorCode::TP_32BIT, | 55 ).Else( |
65 ErrorCode::OP_EQUAL, F_GETFL, | 56 Trap(sandbox::CrashSIGSYS_Handler, NULL) |
66 ErrorCode(ErrorCode::ERR_ALLOWED), | 57 ); |
67 sb->Cond(1, ErrorCode::TP_32BIT, | |
68 ErrorCode::OP_EQUAL, F_SETFL, | |
69 sb->Cond(2, mask_long_type, | |
70 ErrorCode::OP_HAS_ANY_BITS, denied_mask, | |
71 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL), | |
72 ErrorCode(ErrorCode::ERR_ALLOWED)), | |
73 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL)))); | |
74 } | 58 } |
75 | 59 |
76 ErrorCode RestrictClone(SandboxBPF* sb) { | 60 ResultExpr RestrictClone() { |
77 // We allow clone only for new thread creation. | 61 // We allow clone only for new thread creation. |
78 return sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 62 const int kAllowableFlags = |
79 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | | 63 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | |
80 CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS | | 64 CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; |
81 CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID, | 65 const Arg<int> flag_arg(0); |
82 ErrorCode(ErrorCode::ERR_ALLOWED), | 66 return If(flag_arg == kAllowableFlags).Then( |
83 sb->Trap(sandbox::SIGSYSCloneFailure, NULL)); | 67 Allow() |
| 68 ).Else( |
| 69 Trap(sandbox::SIGSYSCloneFailure, NULL) |
| 70 ); |
84 } | 71 } |
85 | 72 |
86 ErrorCode RestrictPrctl(SandboxBPF* sb) { | 73 ResultExpr RestrictPrctl() { |
87 // base::PlatformThread::SetName() uses PR_SET_NAME so we return | 74 // base::PlatformThread::SetName() uses PR_SET_NAME so we return |
88 // EPERM for it. Otherwise, we will raise SIGSYS. | 75 // EPERM for it. Otherwise, we will raise SIGSYS. |
89 return sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 76 const Arg<int> option_arg(0); |
90 PR_SET_NAME, ErrorCode(EPERM), | 77 return If(option_arg == PR_SET_NAME).Then( |
91 sb->Trap(sandbox::SIGSYSPrctlFailure, NULL)); | 78 Error(EPERM) |
| 79 ).Else( |
| 80 Trap(sandbox::SIGSYSPrctlFailure, NULL) |
| 81 ); |
92 } | 82 } |
93 | 83 |
94 #if defined(__i386__) | 84 #if defined(__i386__) |
95 ErrorCode RestrictSocketcall(SandboxBPF* sb) { | 85 ResultExpr RestrictSocketcall() { |
96 // We only allow socketpair, sendmsg, and recvmsg. | 86 // We only allow socketpair, sendmsg, and recvmsg. |
97 return sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 87 const Arg<int> call_arg(0); |
98 SYS_SOCKETPAIR, | 88 return If(call_arg == SYS_SOCKETPAIR || call_arg == SYS_SENDMSG || |
99 ErrorCode(ErrorCode::ERR_ALLOWED), | 89 call_arg == SYS_RECVMSG || call_arg == SYS_SHUTDOWMN).Then( |
100 sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 90 Allow() |
101 SYS_SENDMSG, | 91 ).Else( |
102 ErrorCode(ErrorCode::ERR_ALLOWED), | 92 Trap(sandbox::CrashSIGSYS_Handler, NULL) |
103 sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 93 ); |
104 SYS_RECVMSG, | |
105 ErrorCode(ErrorCode::ERR_ALLOWED), | |
106 sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | |
107 SYS_SHUTDOWN, | |
108 ErrorCode(ErrorCode::ERR_ALLOWED), | |
109 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL))))); | |
110 } | 94 } |
111 #endif | 95 #endif |
112 | 96 |
113 ErrorCode RestrictMprotect(SandboxBPF* sb) { | 97 ResultExpr RestrictMprotect() { |
114 // TODO(jln, keescook, drewry): Limit the use of mprotect by adding | 98 // TODO(jln, keescook, drewry): Limit the use of mprotect by adding |
115 // some features to linux kernel. | 99 // some features to linux kernel. |
116 const uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC); | 100 const uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC); |
117 return sb->Cond(2, ErrorCode::TP_32BIT, | 101 const Arg<int> prot_arg(2); |
118 ErrorCode::OP_HAS_ANY_BITS, | 102 return If((prot_arg & denied_mask) == 0).Then( |
119 denied_mask, | 103 Allow() |
120 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL), | 104 ).Else( |
121 ErrorCode(ErrorCode::ERR_ALLOWED)); | 105 Trap(sandbox::CrashSIGSYS_Handler, NULL) |
| 106 ); |
122 } | 107 } |
123 | 108 |
124 ErrorCode RestrictMmap(SandboxBPF* sb) { | 109 ResultExpr RestrictMmap() { |
125 const uint32_t denied_flag_mask = ~(MAP_SHARED | MAP_PRIVATE | | 110 const uint32_t denied_flag_mask = ~(MAP_SHARED | MAP_PRIVATE | |
126 MAP_ANONYMOUS | MAP_STACK | MAP_FIXED); | 111 MAP_ANONYMOUS | MAP_STACK | MAP_FIXED); |
127 // When PROT_EXEC is specified, IRT mmap of Non-SFI NaCl helper | 112 // When PROT_EXEC is specified, IRT mmap of Non-SFI NaCl helper |
128 // calls mmap without PROT_EXEC and then adds PROT_EXEC by mprotect, | 113 // calls mmap without PROT_EXEC and then adds PROT_EXEC by mprotect, |
129 // so we do not need to allow PROT_EXEC in mmap. | 114 // so we do not need to allow PROT_EXEC in mmap. |
130 const uint32_t denied_prot_mask = ~(PROT_READ | PROT_WRITE); | 115 const uint32_t denied_prot_mask = ~(PROT_READ | PROT_WRITE); |
131 return sb->Cond(3, ErrorCode::TP_32BIT, | 116 const Arg<int> prot_arg(2), flags_arg(3); |
132 ErrorCode::OP_HAS_ANY_BITS, | 117 return If((prot_arg & denied_prot_mask) == 0 && |
133 denied_flag_mask, | 118 (flags_arg & denied_flag_mask) == 0).Then( |
134 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL), | 119 Allow() |
135 sb->Cond(2, ErrorCode::TP_32BIT, | 120 ).Else( |
136 ErrorCode::OP_HAS_ANY_BITS, | 121 Trap(sandbox::CrashSIGSYS_Handler, NULL) |
137 denied_prot_mask, | 122 ); |
138 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL), | |
139 ErrorCode(ErrorCode::ERR_ALLOWED))); | |
140 } | 123 } |
141 | 124 |
142 #if defined(__x86_64__) || defined(__arm__) | 125 #if defined(__x86_64__) || defined(__arm__) |
143 ErrorCode RestrictSocketpair(SandboxBPF* sb) { | 126 ResultExpr RestrictSocketpair() { |
144 // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen. | 127 // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen. |
145 COMPILE_ASSERT(AF_UNIX == PF_UNIX, af_unix_pf_unix_different); | 128 COMPILE_ASSERT(AF_UNIX == PF_UNIX, af_unix_pf_unix_different); |
146 return sb->Cond(0, ErrorCode::TP_32BIT, | 129 const Arg<int> domain_arg(0); |
147 ErrorCode::OP_EQUAL, AF_UNIX, | 130 return If(domain_arg == AF_UNIX).Then( |
148 ErrorCode(ErrorCode::ERR_ALLOWED), | 131 Allow() |
149 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL)); | 132 ).Else( |
| 133 Trap(sandbox::CrashSIGSYS_Handler, NULL) |
| 134 ); |
150 } | 135 } |
151 #endif | 136 #endif |
152 | 137 |
153 bool IsGracefullyDenied(int sysno) { | 138 bool IsGracefullyDenied(int sysno) { |
154 switch (sysno) { | 139 switch (sysno) { |
155 // libevent tries this first and then falls back to poll if | 140 // libevent tries this first and then falls back to poll if |
156 // epoll_create fails. | 141 // epoll_create fails. |
157 case __NR_epoll_create: | 142 case __NR_epoll_create: |
158 // third_party/libevent uses them, but we can just return -1 from | 143 // third_party/libevent uses them, but we can just return -1 from |
159 // them as it is just checking getuid() != geteuid() and | 144 // them as it is just checking getuid() != geteuid() and |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
196 errno = 0; | 181 errno = 0; |
197 // Make a ptrace request with an invalid PID. | 182 // Make a ptrace request with an invalid PID. |
198 long ptrace_ret = ptrace(PTRACE_PEEKUSER, -1 /* pid */, NULL, NULL); | 183 long ptrace_ret = ptrace(PTRACE_PEEKUSER, -1 /* pid */, NULL, NULL); |
199 CHECK_EQ(-1, ptrace_ret); | 184 CHECK_EQ(-1, ptrace_ret); |
200 // Without the sandbox on, this ptrace call would ESRCH instead. | 185 // Without the sandbox on, this ptrace call would ESRCH instead. |
201 CHECK_EQ(EPERM, errno); | 186 CHECK_EQ(EPERM, errno); |
202 } | 187 } |
203 | 188 |
204 } // namespace | 189 } // namespace |
205 | 190 |
206 ErrorCode NaClNonSfiBPFSandboxPolicy::EvaluateSyscall(SandboxBPF* sb, | 191 ResultExpr NaClNonSfiBPFSandboxPolicy::EvaluateSyscall(int sysno) const { |
207 int sysno) const { | |
208 switch (sysno) { | 192 switch (sysno) { |
209 // Allowed syscalls. | 193 // Allowed syscalls. |
210 #if defined(__i386__) || defined(__arm__) | 194 #if defined(__i386__) || defined(__arm__) |
211 case __NR__llseek: | 195 case __NR__llseek: |
212 #elif defined(__x86_64__) | 196 #elif defined(__x86_64__) |
213 case __NR_lseek: | 197 case __NR_lseek: |
214 #endif | 198 #endif |
215 // NaCl runtime exposes clock_gettime and clock_getres to untrusted code. | 199 // NaCl runtime exposes clock_gettime and clock_getres to untrusted code. |
216 case __NR_clock_getres: | 200 case __NR_clock_getres: |
217 case __NR_clock_gettime: | 201 case __NR_clock_gettime: |
(...skipping 25 matching lines...) Expand all Loading... |
243 case __NR_restart_syscall: | 227 case __NR_restart_syscall: |
244 case __NR_sched_yield: | 228 case __NR_sched_yield: |
245 // __NR_times needed as clock() is called by CommandBufferHelper, which is | 229 // __NR_times needed as clock() is called by CommandBufferHelper, which is |
246 // used by NaCl applications that use Pepper's 3D interfaces. | 230 // used by NaCl applications that use Pepper's 3D interfaces. |
247 // See crbug.com/264856 for details. | 231 // See crbug.com/264856 for details. |
248 case __NR_times: | 232 case __NR_times: |
249 case __NR_write: | 233 case __NR_write: |
250 #if defined(__arm__) | 234 #if defined(__arm__) |
251 case __ARM_NR_cacheflush: | 235 case __ARM_NR_cacheflush: |
252 #endif | 236 #endif |
253 return ErrorCode(ErrorCode::ERR_ALLOWED); | 237 return Allow(); |
254 | 238 |
255 case __NR_clone: | 239 case __NR_clone: |
256 return RestrictClone(sb); | 240 return RestrictClone(); |
257 | 241 |
258 #if defined(__x86_64__) | 242 #if defined(__x86_64__) |
259 case __NR_fcntl: | 243 case __NR_fcntl: |
260 #endif | 244 #endif |
261 #if defined(__i386__) || defined(__arm__) | 245 #if defined(__i386__) || defined(__arm__) |
262 case __NR_fcntl64: | 246 case __NR_fcntl64: |
263 #endif | 247 #endif |
264 return RestrictFcntlCommands(sb); | 248 return RestrictFcntlCommands(); |
265 | 249 |
266 #if defined(__x86_64__) | 250 #if defined(__x86_64__) |
267 case __NR_mmap: | 251 case __NR_mmap: |
268 #endif | 252 #endif |
269 #if defined(__i386__) || defined(__arm__) | 253 #if defined(__i386__) || defined(__arm__) |
270 case __NR_mmap2: | 254 case __NR_mmap2: |
271 #endif | 255 #endif |
272 return RestrictMmap(sb); | 256 return RestrictMmap(); |
273 case __NR_mprotect: | 257 case __NR_mprotect: |
274 return RestrictMprotect(sb); | 258 return RestrictMprotect(); |
275 | 259 |
276 case __NR_prctl: | 260 case __NR_prctl: |
277 return RestrictPrctl(sb); | 261 return RestrictPrctl(); |
278 | 262 |
279 #if defined(__i386__) | 263 #if defined(__i386__) |
280 case __NR_socketcall: | 264 case __NR_socketcall: |
281 return RestrictSocketcall(sb); | 265 return RestrictSocketcall(); |
282 #endif | 266 #endif |
283 #if defined(__x86_64__) || defined(__arm__) | 267 #if defined(__x86_64__) || defined(__arm__) |
284 case __NR_recvmsg: | 268 case __NR_recvmsg: |
285 case __NR_sendmsg: | 269 case __NR_sendmsg: |
286 case __NR_shutdown: | 270 case __NR_shutdown: |
287 return ErrorCode(ErrorCode::ERR_ALLOWED); | 271 return Allow(); |
288 case __NR_socketpair: | 272 case __NR_socketpair: |
289 return RestrictSocketpair(sb); | 273 return RestrictSocketpair(); |
290 #endif | 274 #endif |
291 | 275 |
292 case __NR_brk: | 276 case __NR_brk: |
293 // The behavior of brk on Linux is different from other system | 277 // The behavior of brk on Linux is different from other system |
294 // calls. It does not return errno but the current break on | 278 // calls. It does not return errno but the current break on |
295 // failure. glibc thinks brk failed if the return value of brk | 279 // failure. glibc thinks brk failed if the return value of brk |
296 // is less than the requested address (i.e., brk(addr) < addr). | 280 // is less than the requested address (i.e., brk(addr) < addr). |
297 // So, glibc thinks brk succeeded if we return -EPERM and we | 281 // So, glibc thinks brk succeeded if we return -EPERM and we |
298 // need to return zero instead. | 282 // need to return zero instead. |
299 return ErrorCode(0); | 283 return Error(0); |
300 | 284 |
301 default: | 285 default: |
302 if (IsGracefullyDenied(sysno)) | 286 if (IsGracefullyDenied(sysno)) |
303 return ErrorCode(EPERM); | 287 return Error(EPERM); |
304 return sb->Trap(sandbox::CrashSIGSYS_Handler, NULL); | 288 return Trap(sandbox::CrashSIGSYS_Handler, NULL); |
305 } | 289 } |
306 } | 290 } |
307 | 291 |
308 bool InitializeBPFSandbox() { | 292 bool InitializeBPFSandbox() { |
309 bool sandbox_is_initialized = content::InitializeSandbox( | 293 bool sandbox_is_initialized = content::InitializeSandbox( |
310 scoped_ptr<sandbox::SandboxBPFPolicy>( | 294 scoped_ptr<sandbox::SandboxBPFPolicy>( |
311 new nacl::nonsfi::NaClNonSfiBPFSandboxPolicy())); | 295 new nacl::nonsfi::NaClNonSfiBPFSandboxPolicy())); |
312 if (!sandbox_is_initialized) | 296 if (!sandbox_is_initialized) |
313 return false; | 297 return false; |
314 RunSandboxSanityChecks(); | 298 RunSandboxSanityChecks(); |
315 return true; | 299 return true; |
316 } | 300 } |
317 | 301 |
318 } // namespace nonsfi | 302 } // namespace nonsfi |
319 } // namespace nacl | 303 } // namespace nacl |
OLD | NEW |