Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(468)

Side by Side Diff: sandbox/linux/seccomp-bpf/sandbox_bpf.cc

Issue 101773003: Linux sandbox: cleanup sandbox-bpf naming. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rename class Sandbox to class SandboxBPF Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698