OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 5 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
6 | 6 |
7 // Some headers on Android are missing cdefs: crbug.com/172337. | 7 // Some headers on Android are missing cdefs: crbug.com/172337. |
8 // (We can't use OS_ANDROID here since build_config.h is not included). | 8 // (We can't use OS_ANDROID here since build_config.h is not included). |
9 #if defined(ANDROID) | 9 #if defined(ANDROID) |
10 #include <sys/cdefs.h> | 10 #include <sys/cdefs.h> |
(...skipping 12 matching lines...) Expand all Loading... | |
23 #include "base/compiler_specific.h" | 23 #include "base/compiler_specific.h" |
24 #include "base/logging.h" | 24 #include "base/logging.h" |
25 #include "base/memory/scoped_ptr.h" | 25 #include "base/memory/scoped_ptr.h" |
26 #include "base/posix/eintr_wrapper.h" | 26 #include "base/posix/eintr_wrapper.h" |
27 #include "sandbox/linux/seccomp-bpf/codegen.h" | 27 #include "sandbox/linux/seccomp-bpf/codegen.h" |
28 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" | 28 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" |
29 #include "sandbox/linux/seccomp-bpf/syscall.h" | 29 #include "sandbox/linux/seccomp-bpf/syscall.h" |
30 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" | 30 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h" |
31 #include "sandbox/linux/seccomp-bpf/verifier.h" | 31 #include "sandbox/linux/seccomp-bpf/verifier.h" |
32 | 32 |
33 namespace playground2 { | 33 namespace sandbox { |
34 | 34 |
35 namespace { | 35 namespace { |
36 | 36 |
37 const int kExpectedExitCode = 100; | 37 const int kExpectedExitCode = 100; |
38 | 38 |
39 int popcount(uint32_t x) { | 39 int popcount(uint32_t x) { |
40 return __builtin_popcount(x); | 40 return __builtin_popcount(x); |
41 } | 41 } |
42 | 42 |
43 #if !defined(NDEBUG) | 43 #if !defined(NDEBUG) |
44 void WriteFailedStderrSetupMessage(int out_fd) { | 44 void WriteFailedStderrSetupMessage(int out_fd) { |
45 const char* error_string = strerror(errno); | 45 const char* error_string = strerror(errno); |
46 static const char msg[] = | 46 static const char msg[] = |
47 "You have reproduced a puzzling issue.\n" | 47 "You have reproduced a puzzling issue.\n" |
48 "Please, report to crbug.com/152530!\n" | 48 "Please, report to crbug.com/152530!\n" |
49 "Failed to set up stderr: "; | 49 "Failed to set up stderr: "; |
50 if (HANDLE_EINTR(write(out_fd, msg, sizeof(msg) - 1)) > 0 && error_string && | 50 if (HANDLE_EINTR(write(out_fd, msg, sizeof(msg) - 1)) > 0 && error_string && |
51 HANDLE_EINTR(write(out_fd, error_string, strlen(error_string))) > 0 && | 51 HANDLE_EINTR(write(out_fd, error_string, strlen(error_string))) > 0 && |
52 HANDLE_EINTR(write(out_fd, "\n", 1))) { | 52 HANDLE_EINTR(write(out_fd, "\n", 1))) { |
53 } | 53 } |
54 } | 54 } |
55 #endif // !defined(NDEBUG) | 55 #endif // !defined(NDEBUG) |
56 | 56 |
57 // We define a really simple sandbox policy. It is just good enough for us | 57 // We define a really simple sandbox policy. It is just good enough for us |
58 // to tell that the sandbox has actually been activated. | 58 // to tell that the sandbox has actually been activated. |
59 ErrorCode ProbeEvaluator(Sandbox*, int sysnum, void*) __attribute__((const)); | 59 ErrorCode ProbeEvaluator(SandboxBPF*, int sysnum, void*) __attribute__((const)); |
60 ErrorCode ProbeEvaluator(Sandbox*, int sysnum, void*) { | 60 ErrorCode ProbeEvaluator(SandboxBPF*, int sysnum, void*) { |
61 switch (sysnum) { | 61 switch (sysnum) { |
62 case __NR_getpid: | 62 case __NR_getpid: |
63 // Return EPERM so that we can check that the filter actually ran. | 63 // Return EPERM so that we can check that the filter actually ran. |
64 return ErrorCode(EPERM); | 64 return ErrorCode(EPERM); |
65 case __NR_exit_group: | 65 case __NR_exit_group: |
66 // Allow exit() with a non-default return code. | 66 // Allow exit() with a non-default return code. |
67 return ErrorCode(ErrorCode::ERR_ALLOWED); | 67 return ErrorCode(ErrorCode::ERR_ALLOWED); |
68 default: | 68 default: |
69 // Make everything else fail in an easily recognizable way. | 69 // Make everything else fail in an easily recognizable way. |
70 return ErrorCode(EINVAL); | 70 return ErrorCode(EINVAL); |
71 } | 71 } |
72 } | 72 } |
73 | 73 |
74 void ProbeProcess(void) { | 74 void ProbeProcess(void) { |
75 if (syscall(__NR_getpid) < 0 && errno == EPERM) { | 75 if (syscall(__NR_getpid) < 0 && errno == EPERM) { |
76 syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode)); | 76 syscall(__NR_exit_group, static_cast<intptr_t>(kExpectedExitCode)); |
77 } | 77 } |
78 } | 78 } |
79 | 79 |
80 ErrorCode AllowAllEvaluator(Sandbox*, int sysnum, void*) { | 80 ErrorCode AllowAllEvaluator(SandboxBPF*, int sysnum, void*) { |
81 if (!Sandbox::IsValidSyscallNumber(sysnum)) { | 81 if (!SandboxBPF::IsValidSyscallNumber(sysnum)) { |
82 return ErrorCode(ENOSYS); | 82 return ErrorCode(ENOSYS); |
83 } | 83 } |
84 return ErrorCode(ErrorCode::ERR_ALLOWED); | 84 return ErrorCode(ErrorCode::ERR_ALLOWED); |
85 } | 85 } |
86 | 86 |
87 void TryVsyscallProcess(void) { | 87 void TryVsyscallProcess(void) { |
88 time_t current_time; | 88 time_t current_time; |
89 // time() is implemented as a vsyscall. With an older glibc, with | 89 // time() is implemented as a vsyscall. With an older glibc, with |
90 // vsyscall=emulate and some versions of the seccomp BPF patch | 90 // vsyscall=emulate and some versions of the seccomp BPF patch |
91 // we may get SIGKILL-ed. Detect this! | 91 // we may get SIGKILL-ed. Detect this! |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
155 void RedirectToUserspace(Instruction* insn, void* aux) { | 155 void RedirectToUserspace(Instruction* insn, void* aux) { |
156 // When inside an UnsafeTrap() callback, we want to allow all system calls. | 156 // When inside an UnsafeTrap() callback, we want to allow all system calls. |
157 // This means, we must conditionally disable the sandbox -- and that's not | 157 // This means, we must conditionally disable the sandbox -- and that's not |
158 // something that kernel-side BPF filters can do, as they cannot inspect | 158 // something that kernel-side BPF filters can do, as they cannot inspect |
159 // any state other than the syscall arguments. | 159 // any state other than the syscall arguments. |
160 // But if we redirect all error handlers to user-space, then we can easily | 160 // But if we redirect all error handlers to user-space, then we can easily |
161 // make this decision. | 161 // make this decision. |
162 // The performance penalty for this extra round-trip to user-space is not | 162 // The performance penalty for this extra round-trip to user-space is not |
163 // actually that bad, as we only ever pay it for denied system calls; and a | 163 // actually that bad, as we only ever pay it for denied system calls; and a |
164 // typical program has very few of these. | 164 // typical program has very few of these. |
165 Sandbox* sandbox = static_cast<Sandbox*>(aux); | 165 SandboxBPF* sandbox = static_cast<SandboxBPF*>(aux); |
166 if (BPF_CLASS(insn->code) == BPF_RET && | 166 if (BPF_CLASS(insn->code) == BPF_RET && |
167 (insn->k & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) { | 167 (insn->k & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) { |
168 insn->k = sandbox->Trap(ReturnErrno, | 168 insn->k = sandbox->Trap(ReturnErrno, |
169 reinterpret_cast<void*>(insn->k & SECCOMP_RET_DATA)).err(); | 169 reinterpret_cast<void*>(insn->k & SECCOMP_RET_DATA)).err(); |
170 } | 170 } |
171 } | 171 } |
172 | 172 |
173 // This wraps an existing policy and changes its behavior to match the changes | 173 // This wraps an existing policy and changes its behavior to match the changes |
174 // made by RedirectToUserspace(). This is part of the framework that allows BPF | 174 // made by RedirectToUserspace(). This is part of the framework that allows BPF |
175 // evaluation in userland. | 175 // evaluation in userland. |
176 // TODO(markus): document the code inside better. | 176 // TODO(markus): document the code inside better. |
177 class RedirectToUserSpacePolicyWrapper : public SandboxBpfPolicy { | 177 class RedirectToUserSpacePolicyWrapper : public SandboxBpfPolicy { |
178 public: | 178 public: |
179 explicit RedirectToUserSpacePolicyWrapper( | 179 explicit RedirectToUserSpacePolicyWrapper( |
180 const SandboxBpfPolicy* wrapped_policy) | 180 const SandboxBpfPolicy* wrapped_policy) |
181 : wrapped_policy_(wrapped_policy) { | 181 : wrapped_policy_(wrapped_policy) { |
182 DCHECK(wrapped_policy_); | 182 DCHECK(wrapped_policy_); |
183 } | 183 } |
184 | 184 |
185 virtual ErrorCode EvaluateSyscall(Sandbox* sandbox_compiler, | 185 virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler, |
186 int system_call_number) const OVERRIDE { | 186 int system_call_number) const OVERRIDE { |
187 ErrorCode err = | 187 ErrorCode err = |
188 wrapped_policy_->EvaluateSyscall(sandbox_compiler, system_call_number); | 188 wrapped_policy_->EvaluateSyscall(sandbox_compiler, system_call_number); |
189 if ((err.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) { | 189 if ((err.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) { |
190 return sandbox_compiler->Trap( | 190 return sandbox_compiler->Trap( |
191 ReturnErrno, reinterpret_cast<void*>(err.err() & SECCOMP_RET_DATA)); | 191 ReturnErrno, reinterpret_cast<void*>(err.err() & SECCOMP_RET_DATA)); |
192 } | 192 } |
193 return err; | 193 return err; |
194 } | 194 } |
195 | 195 |
196 private: | 196 private: |
197 const SandboxBpfPolicy* wrapped_policy_; | 197 const SandboxBpfPolicy* wrapped_policy_; |
198 DISALLOW_COPY_AND_ASSIGN(RedirectToUserSpacePolicyWrapper); | 198 DISALLOW_COPY_AND_ASSIGN(RedirectToUserSpacePolicyWrapper); |
199 }; | 199 }; |
200 | 200 |
201 intptr_t BpfFailure(const struct arch_seccomp_data&, void* aux) { | 201 intptr_t BpfFailure(const struct arch_seccomp_data&, void* aux) { |
202 SANDBOX_DIE(static_cast<char*>(aux)); | 202 SANDBOX_DIE(static_cast<char*>(aux)); |
203 } | 203 } |
204 | 204 |
205 // This class allows compatibility with the old, deprecated SetSandboxPolicy. | 205 // This class allows compatibility with the old, deprecated SetSandboxPolicy. |
206 class CompatibilityPolicy : public SandboxBpfPolicy { | 206 class CompatibilityPolicy : public SandboxBpfPolicy { |
207 public: | 207 public: |
208 CompatibilityPolicy(Sandbox::EvaluateSyscall syscall_evaluator, void* aux) | 208 CompatibilityPolicy(SandboxBPF::EvaluateSyscall syscall_evaluator, void* aux) |
209 : syscall_evaluator_(syscall_evaluator), aux_(aux) { | 209 : syscall_evaluator_(syscall_evaluator), aux_(aux) { |
210 DCHECK(syscall_evaluator_); | 210 DCHECK(syscall_evaluator_); |
211 } | 211 } |
212 | 212 |
213 virtual ErrorCode EvaluateSyscall(Sandbox* sandbox_compiler, | 213 virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler, |
214 int system_call_number) const OVERRIDE { | 214 int system_call_number) const OVERRIDE { |
215 return syscall_evaluator_(sandbox_compiler, system_call_number, aux_); | 215 return syscall_evaluator_(sandbox_compiler, system_call_number, aux_); |
216 } | 216 } |
217 | 217 |
218 private: | 218 private: |
219 Sandbox::EvaluateSyscall syscall_evaluator_; | 219 SandboxBPF::EvaluateSyscall syscall_evaluator_; |
220 void* aux_; | 220 void* aux_; |
221 DISALLOW_COPY_AND_ASSIGN(CompatibilityPolicy); | 221 DISALLOW_COPY_AND_ASSIGN(CompatibilityPolicy); |
222 }; | 222 }; |
223 | 223 |
224 } // namespace | 224 } // namespace |
225 | 225 |
226 Sandbox::Sandbox() | 226 SandboxBPF::SandboxBPF() |
227 : quiet_(false), | 227 : quiet_(false), |
228 proc_fd_(-1), | 228 proc_fd_(-1), |
229 conds_(new Conds), | 229 conds_(new Conds), |
230 sandbox_has_started_(false) {} | 230 sandbox_has_started_(false) {} |
231 | 231 |
232 Sandbox::~Sandbox() { | 232 SandboxBPF::~SandboxBPF() { |
233 // It is generally unsafe to call any memory allocator operations or to even | 233 // It is generally unsafe to call any memory allocator operations or to even |
234 // call arbitrary destructors after having installed a new policy. We just | 234 // call arbitrary destructors after having installed a new policy. We just |
235 // have no way to tell whether this policy would allow the system calls that | 235 // have no way to tell whether this policy would allow the system calls that |
236 // the constructors can trigger. | 236 // the constructors can trigger. |
237 // So, we normally destroy all of our complex state prior to starting the | 237 // So, we normally destroy all of our complex state prior to starting the |
238 // sandbox. But this won't happen, if the Sandbox object was created and | 238 // sandbox. But this won't happen, if the Sandbox object was created and |
239 // never actually used to set up a sandbox. So, just in case, we are | 239 // never actually used to set up a sandbox. So, just in case, we are |
240 // destroying any remaining state. | 240 // destroying any remaining state. |
241 // The "if ()" statements are technically superfluous. But let's be explicit | 241 // The "if ()" statements are technically superfluous. But let's be explicit |
242 // that we really don't want to run any code, when we already destroyed | 242 // that we really don't want to run any code, when we already destroyed |
243 // objects before setting up the sandbox. | 243 // objects before setting up the sandbox. |
244 if (conds_) { | 244 if (conds_) { |
245 delete conds_; | 245 delete conds_; |
246 } | 246 } |
247 } | 247 } |
248 | 248 |
249 bool Sandbox::IsValidSyscallNumber(int sysnum) { | 249 bool SandboxBPF::IsValidSyscallNumber(int sysnum) { |
250 return SyscallIterator::IsValid(sysnum); | 250 return SyscallIterator::IsValid(sysnum); |
251 } | 251 } |
252 | 252 |
253 bool Sandbox::RunFunctionInPolicy(void (*code_in_sandbox)(), | 253 bool SandboxBPF::RunFunctionInPolicy(void (*code_in_sandbox)(), |
254 Sandbox::EvaluateSyscall syscall_evaluator, | 254 SandboxBPF::EvaluateSyscall syscall_evaluator, |
Robert Sesek
2013/12/10 15:07:46
nit: alignment. Since this won't fit in 80cols, ju
jln (very slow on Chromium)
2013/12/10 18:43:47
Done. (Removed useless SandboxBPF::)
| |
255 void* aux) { | 255 void* aux) { |
256 // Block all signals before forking a child process. This prevents an | 256 // Block all signals before forking a child process. This prevents an |
257 // attacker from manipulating our test by sending us an unexpected signal. | 257 // attacker from manipulating our test by sending us an unexpected signal. |
258 sigset_t old_mask, new_mask; | 258 sigset_t old_mask, new_mask; |
259 if (sigfillset(&new_mask) || sigprocmask(SIG_BLOCK, &new_mask, &old_mask)) { | 259 if (sigfillset(&new_mask) || sigprocmask(SIG_BLOCK, &new_mask, &old_mask)) { |
260 SANDBOX_DIE("sigprocmask() failed"); | 260 SANDBOX_DIE("sigprocmask() failed"); |
261 } | 261 } |
262 int fds[2]; | 262 int fds[2]; |
263 if (pipe2(fds, O_NONBLOCK | O_CLOEXEC)) { | 263 if (pipe2(fds, O_NONBLOCK | O_CLOEXEC)) { |
264 SANDBOX_DIE("pipe() failed"); | 264 SANDBOX_DIE("pipe() failed"); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
357 SANDBOX_DIE(buf); | 357 SANDBOX_DIE(buf); |
358 } | 358 } |
359 } | 359 } |
360 if (IGNORE_EINTR(close(fds[0]))) { | 360 if (IGNORE_EINTR(close(fds[0]))) { |
361 SANDBOX_DIE("close() failed"); | 361 SANDBOX_DIE("close() failed"); |
362 } | 362 } |
363 | 363 |
364 return rc; | 364 return rc; |
365 } | 365 } |
366 | 366 |
367 bool Sandbox::KernelSupportSeccompBPF() { | 367 bool SandboxBPF::KernelSupportSeccompBPF() { |
368 return RunFunctionInPolicy(ProbeProcess, ProbeEvaluator, 0) && | 368 return RunFunctionInPolicy(ProbeProcess, ProbeEvaluator, 0) && |
369 RunFunctionInPolicy(TryVsyscallProcess, AllowAllEvaluator, 0); | 369 RunFunctionInPolicy(TryVsyscallProcess, AllowAllEvaluator, 0); |
370 } | 370 } |
371 | 371 |
372 Sandbox::SandboxStatus Sandbox::SupportsSeccompSandbox(int proc_fd) { | 372 SandboxBPF::SandboxStatus SandboxBPF::SupportsSeccompSandbox(int proc_fd) { |
373 // It the sandbox is currently active, we clearly must have support for | 373 // It the sandbox is currently active, we clearly must have support for |
374 // sandboxing. | 374 // sandboxing. |
375 if (status_ == STATUS_ENABLED) { | 375 if (status_ == STATUS_ENABLED) { |
376 return status_; | 376 return status_; |
377 } | 377 } |
378 | 378 |
379 // Even if the sandbox was previously available, something might have | 379 // Even if the sandbox was previously available, something might have |
380 // changed in our run-time environment. Check one more time. | 380 // changed in our run-time environment. Check one more time. |
381 if (status_ == STATUS_AVAILABLE) { | 381 if (status_ == STATUS_AVAILABLE) { |
382 if (!IsSingleThreaded(proc_fd)) { | 382 if (!IsSingleThreaded(proc_fd)) { |
(...skipping 14 matching lines...) Expand all Loading... | |
397 return status_; | 397 return status_; |
398 } | 398 } |
399 | 399 |
400 // If we have not previously checked for availability of the sandbox or if | 400 // If we have not previously checked for availability of the sandbox or if |
401 // we otherwise don't believe to have a good cached value, we have to | 401 // we otherwise don't believe to have a good cached value, we have to |
402 // perform a thorough check now. | 402 // perform a thorough check now. |
403 if (status_ == STATUS_UNKNOWN) { | 403 if (status_ == STATUS_UNKNOWN) { |
404 // We create our own private copy of a "Sandbox" object. This ensures that | 404 // We create our own private copy of a "Sandbox" object. This ensures that |
405 // the object does not have any policies configured, that might interfere | 405 // the object does not have any policies configured, that might interfere |
406 // with the tests done by "KernelSupportSeccompBPF()". | 406 // with the tests done by "KernelSupportSeccompBPF()". |
407 Sandbox sandbox; | 407 SandboxBPF sandbox; |
408 | 408 |
409 // By setting "quiet_ = true" we suppress messages for expected and benign | 409 // By setting "quiet_ = true" we suppress messages for expected and benign |
410 // failures (e.g. if the current kernel lacks support for BPF filters). | 410 // failures (e.g. if the current kernel lacks support for BPF filters). |
411 sandbox.quiet_ = true; | 411 sandbox.quiet_ = true; |
412 sandbox.set_proc_fd(proc_fd); | 412 sandbox.set_proc_fd(proc_fd); |
413 status_ = sandbox.KernelSupportSeccompBPF() ? STATUS_AVAILABLE | 413 status_ = sandbox.KernelSupportSeccompBPF() ? STATUS_AVAILABLE |
414 : STATUS_UNSUPPORTED; | 414 : STATUS_UNSUPPORTED; |
415 | 415 |
416 // As we are performing our tests from a child process, the run-time | 416 // As we are performing our tests from a child process, the run-time |
417 // environment that is visible to the sandbox is always guaranteed to be | 417 // environment that is visible to the sandbox is always guaranteed to be |
418 // single-threaded. Let's check here whether the caller is single- | 418 // single-threaded. Let's check here whether the caller is single- |
419 // threaded. Otherwise, we mark the sandbox as temporarily unavailable. | 419 // threaded. Otherwise, we mark the sandbox as temporarily unavailable. |
420 if (status_ == STATUS_AVAILABLE && !IsSingleThreaded(proc_fd)) { | 420 if (status_ == STATUS_AVAILABLE && !IsSingleThreaded(proc_fd)) { |
421 status_ = STATUS_UNAVAILABLE; | 421 status_ = STATUS_UNAVAILABLE; |
422 } | 422 } |
423 } | 423 } |
424 return status_; | 424 return status_; |
425 } | 425 } |
426 | 426 |
427 void Sandbox::set_proc_fd(int proc_fd) { proc_fd_ = proc_fd; } | 427 void SandboxBPF::set_proc_fd(int proc_fd) { proc_fd_ = proc_fd; } |
428 | 428 |
429 void Sandbox::StartSandbox() { | 429 void SandboxBPF::StartSandbox() { |
430 if (status_ == STATUS_UNSUPPORTED || status_ == STATUS_UNAVAILABLE) { | 430 if (status_ == STATUS_UNSUPPORTED || status_ == STATUS_UNAVAILABLE) { |
431 SANDBOX_DIE( | 431 SANDBOX_DIE( |
432 "Trying to start sandbox, even though it is known to be " | 432 "Trying to start sandbox, even though it is known to be " |
433 "unavailable"); | 433 "unavailable"); |
434 } else if (sandbox_has_started_ || !conds_) { | 434 } else if (sandbox_has_started_ || !conds_) { |
435 SANDBOX_DIE( | 435 SANDBOX_DIE( |
436 "Cannot repeatedly start sandbox. Create a separate Sandbox " | 436 "Cannot repeatedly start sandbox. Create a separate Sandbox " |
437 "object instead."); | 437 "object instead."); |
438 } | 438 } |
439 if (proc_fd_ < 0) { | 439 if (proc_fd_ < 0) { |
(...skipping 17 matching lines...) Expand all Loading... | |
457 proc_fd_ = -1; | 457 proc_fd_ = -1; |
458 } | 458 } |
459 | 459 |
460 // Install the filters. | 460 // Install the filters. |
461 InstallFilter(); | 461 InstallFilter(); |
462 | 462 |
463 // We are now inside the sandbox. | 463 // We are now inside the sandbox. |
464 status_ = STATUS_ENABLED; | 464 status_ = STATUS_ENABLED; |
465 } | 465 } |
466 | 466 |
467 void Sandbox::PolicySanityChecks(SandboxBpfPolicy* policy) { | 467 void SandboxBPF::PolicySanityChecks(SandboxBpfPolicy* policy) { |
468 for (SyscallIterator iter(true); !iter.Done();) { | 468 for (SyscallIterator iter(true); !iter.Done();) { |
469 uint32_t sysnum = iter.Next(); | 469 uint32_t sysnum = iter.Next(); |
470 if (!IsDenied(policy->EvaluateSyscall(this, sysnum))) { | 470 if (!IsDenied(policy->EvaluateSyscall(this, sysnum))) { |
471 SANDBOX_DIE( | 471 SANDBOX_DIE( |
472 "Policies should deny system calls that are outside the " | 472 "Policies should deny system calls that are outside the " |
473 "expected range (typically MIN_SYSCALL..MAX_SYSCALL)"); | 473 "expected range (typically MIN_SYSCALL..MAX_SYSCALL)"); |
474 } | 474 } |
475 } | 475 } |
476 return; | 476 return; |
477 } | 477 } |
478 | 478 |
479 // Deprecated API, supported with a wrapper to the new API. | 479 // Deprecated API, supported with a wrapper to the new API. |
480 void Sandbox::SetSandboxPolicyDeprecated(EvaluateSyscall syscall_evaluator, | 480 void SandboxBPF::SetSandboxPolicyDeprecated(EvaluateSyscall syscall_evaluator, |
481 void* aux) { | 481 void* aux) { |
Robert Sesek
2013/12/10 15:07:46
nit: alignment
jln (very slow on Chromium)
2013/12/10 18:43:47
Done.
| |
482 if (sandbox_has_started_ || !conds_) { | 482 if (sandbox_has_started_ || !conds_) { |
483 SANDBOX_DIE("Cannot change policy after sandbox has started"); | 483 SANDBOX_DIE("Cannot change policy after sandbox has started"); |
484 } | 484 } |
485 SetSandboxPolicy(new CompatibilityPolicy(syscall_evaluator, aux)); | 485 SetSandboxPolicy(new CompatibilityPolicy(syscall_evaluator, aux)); |
486 } | 486 } |
487 | 487 |
488 // Don't take a scoped_ptr here, polymorphism make their use awkward. | 488 // Don't take a scoped_ptr here, polymorphism make their use awkward. |
489 void Sandbox::SetSandboxPolicy(SandboxBpfPolicy* policy) { | 489 void SandboxBPF::SetSandboxPolicy(SandboxBpfPolicy* policy) { |
490 DCHECK(!policy_); | 490 DCHECK(!policy_); |
491 if (sandbox_has_started_ || !conds_) { | 491 if (sandbox_has_started_ || !conds_) { |
492 SANDBOX_DIE("Cannot change policy after sandbox has started"); | 492 SANDBOX_DIE("Cannot change policy after sandbox has started"); |
493 } | 493 } |
494 PolicySanityChecks(policy); | 494 PolicySanityChecks(policy); |
495 policy_.reset(policy); | 495 policy_.reset(policy); |
496 } | 496 } |
497 | 497 |
498 void Sandbox::InstallFilter() { | 498 void SandboxBPF::InstallFilter() { |
499 // We want to be very careful in not imposing any requirements on the | 499 // We want to be very careful in not imposing any requirements on the |
500 // policies that are set with SetSandboxPolicy(). This means, as soon as | 500 // policies that are set with SetSandboxPolicy(). This means, as soon as |
501 // the sandbox is active, we shouldn't be relying on libraries that could | 501 // the sandbox is active, we shouldn't be relying on libraries that could |
502 // be making system calls. This, for example, means we should avoid | 502 // be making system calls. This, for example, means we should avoid |
503 // using the heap and we should avoid using STL functions. | 503 // using the heap and we should avoid using STL functions. |
504 // Temporarily copy the contents of the "program" vector into a | 504 // Temporarily copy the contents of the "program" vector into a |
505 // stack-allocated array; and then explicitly destroy that object. | 505 // stack-allocated array; and then explicitly destroy that object. |
506 // This makes sure we don't ex- or implicitly call new/delete after we | 506 // This makes sure we don't ex- or implicitly call new/delete after we |
507 // installed the BPF filter program in the kernel. Depending on the | 507 // installed the BPF filter program in the kernel. Depending on the |
508 // system memory allocator that is in effect, these operators can result | 508 // system memory allocator that is in effect, these operators can result |
(...skipping 20 matching lines...) Expand all Loading... | |
529 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { | 529 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { |
530 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to turn on BPF filters"); | 530 SANDBOX_DIE(quiet_ ? NULL : "Kernel refuses to turn on BPF filters"); |
531 } | 531 } |
532 } | 532 } |
533 | 533 |
534 sandbox_has_started_ = true; | 534 sandbox_has_started_ = true; |
535 | 535 |
536 return; | 536 return; |
537 } | 537 } |
538 | 538 |
539 Sandbox::Program* Sandbox::AssembleFilter(bool force_verification) { | 539 SandboxBPF::Program* SandboxBPF::AssembleFilter(bool force_verification) { |
540 #if !defined(NDEBUG) | 540 #if !defined(NDEBUG) |
541 force_verification = true; | 541 force_verification = true; |
542 #endif | 542 #endif |
543 | 543 |
544 // Verify that the user pushed a policy. | 544 // Verify that the user pushed a policy. |
545 DCHECK(policy_); | 545 DCHECK(policy_); |
546 | 546 |
547 // Assemble the BPF filter program. | 547 // Assemble the BPF filter program. |
548 CodeGen* gen = new CodeGen(); | 548 CodeGen* gen = new CodeGen(); |
549 if (!gen) { | 549 if (!gen) { |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
702 if (force_verification) { | 702 if (force_verification) { |
703 // Verification is expensive. We only perform this step, if we are | 703 // Verification is expensive. We only perform this step, if we are |
704 // compiled in debug mode, or if the caller explicitly requested | 704 // compiled in debug mode, or if the caller explicitly requested |
705 // verification. | 705 // verification. |
706 VerifyProgram(*program, has_unsafe_traps); | 706 VerifyProgram(*program, has_unsafe_traps); |
707 } | 707 } |
708 | 708 |
709 return program; | 709 return program; |
710 } | 710 } |
711 | 711 |
712 void Sandbox::VerifyProgram(const Program& program, bool has_unsafe_traps) { | 712 void SandboxBPF::VerifyProgram(const Program& program, bool has_unsafe_traps) { |
713 // If we previously rewrote the BPF program so that it calls user-space | 713 // If we previously rewrote the BPF program so that it calls user-space |
714 // whenever we return an "errno" value from the filter, then we have to | 714 // whenever we return an "errno" value from the filter, then we have to |
715 // wrap our system call evaluator to perform the same operation. Otherwise, | 715 // wrap our system call evaluator to perform the same operation. Otherwise, |
716 // the verifier would also report a mismatch in return codes. | 716 // the verifier would also report a mismatch in return codes. |
717 scoped_ptr<const RedirectToUserSpacePolicyWrapper> redirected_policy( | 717 scoped_ptr<const RedirectToUserSpacePolicyWrapper> redirected_policy( |
718 new RedirectToUserSpacePolicyWrapper(policy_.get())); | 718 new RedirectToUserSpacePolicyWrapper(policy_.get())); |
719 | 719 |
720 const char* err = NULL; | 720 const char* err = NULL; |
721 if (!Verifier::VerifyBPF(this, | 721 if (!Verifier::VerifyBPF(this, |
722 program, | 722 program, |
723 has_unsafe_traps ? *redirected_policy : *policy_, | 723 has_unsafe_traps ? *redirected_policy : *policy_, |
724 &err)) { | 724 &err)) { |
725 CodeGen::PrintProgram(program); | 725 CodeGen::PrintProgram(program); |
726 SANDBOX_DIE(err); | 726 SANDBOX_DIE(err); |
727 } | 727 } |
728 } | 728 } |
729 | 729 |
730 void Sandbox::FindRanges(Ranges* ranges) { | 730 void SandboxBPF::FindRanges(Ranges* ranges) { |
731 // Please note that "struct seccomp_data" defines system calls as a signed | 731 // Please note that "struct seccomp_data" defines system calls as a signed |
732 // int32_t, but BPF instructions always operate on unsigned quantities. We | 732 // int32_t, but BPF instructions always operate on unsigned quantities. We |
733 // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL, | 733 // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL, |
734 // and then verifying that the rest of the number range (both positive and | 734 // and then verifying that the rest of the number range (both positive and |
735 // negative) all return the same ErrorCode. | 735 // negative) all return the same ErrorCode. |
736 uint32_t old_sysnum = 0; | 736 uint32_t old_sysnum = 0; |
737 ErrorCode old_err = policy_->EvaluateSyscall(this, old_sysnum); | 737 ErrorCode old_err = policy_->EvaluateSyscall(this, old_sysnum); |
738 ErrorCode invalid_err = policy_->EvaluateSyscall(this, MIN_SYSCALL - 1); | 738 ErrorCode invalid_err = policy_->EvaluateSyscall(this, MIN_SYSCALL - 1); |
739 | 739 |
740 for (SyscallIterator iter(false); !iter.Done();) { | 740 for (SyscallIterator iter(false); !iter.Done();) { |
741 uint32_t sysnum = iter.Next(); | 741 uint32_t sysnum = iter.Next(); |
742 ErrorCode err = policy_->EvaluateSyscall(this, static_cast<int>(sysnum)); | 742 ErrorCode err = policy_->EvaluateSyscall(this, static_cast<int>(sysnum)); |
743 if (!iter.IsValid(sysnum) && !invalid_err.Equals(err)) { | 743 if (!iter.IsValid(sysnum) && !invalid_err.Equals(err)) { |
744 // A proper sandbox policy should always treat system calls outside of | 744 // A proper sandbox policy should always treat system calls outside of |
745 // the range MIN_SYSCALL..MAX_SYSCALL (i.e. anything that returns | 745 // the range MIN_SYSCALL..MAX_SYSCALL (i.e. anything that returns |
746 // "false" for SyscallIterator::IsValid()) identically. Typically, all | 746 // "false" for SyscallIterator::IsValid()) identically. Typically, all |
747 // of these system calls would be denied with the same ErrorCode. | 747 // of these system calls would be denied with the same ErrorCode. |
748 SANDBOX_DIE("Invalid seccomp policy"); | 748 SANDBOX_DIE("Invalid seccomp policy"); |
749 } | 749 } |
750 if (!err.Equals(old_err) || iter.Done()) { | 750 if (!err.Equals(old_err) || iter.Done()) { |
751 ranges->push_back(Range(old_sysnum, sysnum - 1, old_err)); | 751 ranges->push_back(Range(old_sysnum, sysnum - 1, old_err)); |
752 old_sysnum = sysnum; | 752 old_sysnum = sysnum; |
753 old_err = err; | 753 old_err = err; |
754 } | 754 } |
755 } | 755 } |
756 } | 756 } |
757 | 757 |
758 Instruction* Sandbox::AssembleJumpTable(CodeGen* gen, | 758 Instruction* SandboxBPF::AssembleJumpTable(CodeGen* gen, |
759 Ranges::const_iterator start, | 759 Ranges::const_iterator start, |
760 Ranges::const_iterator stop) { | 760 Ranges::const_iterator stop) { |
761 // We convert the list of system call ranges into jump table that performs | 761 // We convert the list of system call ranges into jump table that performs |
762 // a binary search over the ranges. | 762 // a binary search over the ranges. |
763 // As a sanity check, we need to have at least one distinct ranges for us | 763 // As a sanity check, we need to have at least one distinct ranges for us |
764 // to be able to build a jump table. | 764 // to be able to build a jump table. |
765 if (stop - start <= 0) { | 765 if (stop - start <= 0) { |
766 SANDBOX_DIE("Invalid set of system call ranges"); | 766 SANDBOX_DIE("Invalid set of system call ranges"); |
767 } else if (stop - start == 1) { | 767 } else if (stop - start == 1) { |
768 // If we have narrowed things down to a single range object, we can | 768 // If we have narrowed things down to a single range object, we can |
769 // return from the BPF filter program. | 769 // return from the BPF filter program. |
770 return RetExpression(gen, start->err); | 770 return RetExpression(gen, start->err); |
771 } | 771 } |
772 | 772 |
773 // Pick the range object that is located at the mid point of our list. | 773 // Pick the range object that is located at the mid point of our list. |
774 // We compare our system call number against the lowest valid system call | 774 // We compare our system call number against the lowest valid system call |
775 // number in this range object. If our number is lower, it is outside of | 775 // number in this range object. If our number is lower, it is outside of |
776 // this range object. If it is greater or equal, it might be inside. | 776 // this range object. If it is greater or equal, it might be inside. |
777 Ranges::const_iterator mid = start + (stop - start) / 2; | 777 Ranges::const_iterator mid = start + (stop - start) / 2; |
778 | 778 |
779 // Sub-divide the list of ranges and continue recursively. | 779 // Sub-divide the list of ranges and continue recursively. |
780 Instruction* jf = AssembleJumpTable(gen, start, mid); | 780 Instruction* jf = AssembleJumpTable(gen, start, mid); |
781 Instruction* jt = AssembleJumpTable(gen, mid, stop); | 781 Instruction* jt = AssembleJumpTable(gen, mid, stop); |
782 return gen->MakeInstruction(BPF_JMP + BPF_JGE + BPF_K, mid->from, jt, jf); | 782 return gen->MakeInstruction(BPF_JMP + BPF_JGE + BPF_K, mid->from, jt, jf); |
783 } | 783 } |
784 | 784 |
785 Instruction* Sandbox::RetExpression(CodeGen* gen, const ErrorCode& err) { | 785 Instruction* SandboxBPF::RetExpression(CodeGen* gen, const ErrorCode& err) { |
786 if (err.error_type_ == ErrorCode::ET_COND) { | 786 if (err.error_type_ == ErrorCode::ET_COND) { |
787 return CondExpression(gen, err); | 787 return CondExpression(gen, err); |
788 } else { | 788 } else { |
789 return gen->MakeInstruction(BPF_RET + BPF_K, err); | 789 return gen->MakeInstruction(BPF_RET + BPF_K, err); |
790 } | 790 } |
791 } | 791 } |
792 | 792 |
793 Instruction* Sandbox::CondExpression(CodeGen* gen, const ErrorCode& cond) { | 793 Instruction* SandboxBPF::CondExpression(CodeGen* gen, const ErrorCode& cond) { |
794 // We can only inspect the six system call arguments that are passed in | 794 // We can only inspect the six system call arguments that are passed in |
795 // CPU registers. | 795 // CPU registers. |
796 if (cond.argno_ < 0 || cond.argno_ >= 6) { | 796 if (cond.argno_ < 0 || cond.argno_ >= 6) { |
797 SANDBOX_DIE( | 797 SANDBOX_DIE( |
798 "Internal compiler error; invalid argument number " | 798 "Internal compiler error; invalid argument number " |
799 "encountered"); | 799 "encountered"); |
800 } | 800 } |
801 | 801 |
802 // BPF programs operate on 32bit entities. Load both halfs of the 64bit | 802 // BPF programs operate on 32bit entities. Load both halfs of the 64bit |
803 // system call argument and then generate suitable conditional statements. | 803 // system call argument and then generate suitable conditional statements. |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
966 #endif | 966 #endif |
967 gen->JoinInstructions( | 967 gen->JoinInstructions( |
968 msb_tail, | 968 msb_tail, |
969 gen->MakeInstruction( | 969 gen->MakeInstruction( |
970 BPF_JMP + BPF_JEQ + BPF_K, 0, lsb_head, invalid_64bit)); | 970 BPF_JMP + BPF_JEQ + BPF_K, 0, lsb_head, invalid_64bit)); |
971 } | 971 } |
972 | 972 |
973 return msb_head; | 973 return msb_head; |
974 } | 974 } |
975 | 975 |
976 ErrorCode Sandbox::Unexpected64bitArgument() { | 976 ErrorCode SandboxBPF::Unexpected64bitArgument() { |
977 return Kill("Unexpected 64bit argument detected"); | 977 return Kill("Unexpected 64bit argument detected"); |
978 } | 978 } |
979 | 979 |
980 ErrorCode Sandbox::Trap(Trap::TrapFnc fnc, const void* aux) { | 980 ErrorCode SandboxBPF::Trap(Trap::TrapFnc fnc, const void* aux) { |
981 return Trap::MakeTrap(fnc, aux, true /* Safe Trap */); | 981 return Trap::MakeTrap(fnc, aux, true /* Safe Trap */); |
982 } | 982 } |
983 | 983 |
984 ErrorCode Sandbox::UnsafeTrap(Trap::TrapFnc fnc, const void* aux) { | 984 ErrorCode SandboxBPF::UnsafeTrap(Trap::TrapFnc fnc, const void* aux) { |
985 return Trap::MakeTrap(fnc, aux, false /* Unsafe Trap */); | 985 return Trap::MakeTrap(fnc, aux, false /* Unsafe Trap */); |
986 } | 986 } |
987 | 987 |
988 intptr_t Sandbox::ForwardSyscall(const struct arch_seccomp_data& args) { | 988 intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) { |
989 return SandboxSyscall(args.nr, | 989 return SandboxSyscall(args.nr, |
990 static_cast<intptr_t>(args.args[0]), | 990 static_cast<intptr_t>(args.args[0]), |
991 static_cast<intptr_t>(args.args[1]), | 991 static_cast<intptr_t>(args.args[1]), |
992 static_cast<intptr_t>(args.args[2]), | 992 static_cast<intptr_t>(args.args[2]), |
993 static_cast<intptr_t>(args.args[3]), | 993 static_cast<intptr_t>(args.args[3]), |
994 static_cast<intptr_t>(args.args[4]), | 994 static_cast<intptr_t>(args.args[4]), |
995 static_cast<intptr_t>(args.args[5])); | 995 static_cast<intptr_t>(args.args[5])); |
996 } | 996 } |
997 | 997 |
998 ErrorCode Sandbox::Cond(int argno, | 998 ErrorCode SandboxBPF::Cond(int argno, |
999 ErrorCode::ArgType width, | 999 ErrorCode::ArgType width, |
Robert Sesek
2013/12/10 15:07:46
nit: alignment
jln (very slow on Chromium)
2013/12/10 18:43:47
Done.
| |
1000 ErrorCode::Operation op, | 1000 ErrorCode::Operation op, |
1001 uint64_t value, | 1001 uint64_t value, |
1002 const ErrorCode& passed, | 1002 const ErrorCode& passed, |
1003 const ErrorCode& failed) { | 1003 const ErrorCode& failed) { |
1004 return ErrorCode(argno, | 1004 return ErrorCode(argno, |
1005 width, | 1005 width, |
1006 op, | 1006 op, |
1007 value, | 1007 value, |
1008 &*conds_->insert(passed).first, | 1008 &*conds_->insert(passed).first, |
1009 &*conds_->insert(failed).first); | 1009 &*conds_->insert(failed).first); |
1010 } | 1010 } |
1011 | 1011 |
1012 ErrorCode Sandbox::Kill(const char* msg) { | 1012 ErrorCode SandboxBPF::Kill(const char* msg) { |
1013 return Trap(BpfFailure, const_cast<char*>(msg)); | 1013 return Trap(BpfFailure, const_cast<char*>(msg)); |
1014 } | 1014 } |
1015 | 1015 |
1016 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; | 1016 SandboxBPF::SandboxStatus SandboxBPF::status_ = STATUS_UNKNOWN; |
1017 | 1017 |
1018 } // namespace playground2 | 1018 } // namespace sandbox |
OLD | NEW |