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

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

Issue 10833044: Refactored ErrorCode into it's own class (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Cosmetic changes Created 8 years, 3 months 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 <time.h> 5 #include <time.h>
6 6
7 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 7 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
8 #include "sandbox/linux/seccomp-bpf/verifier.h" 8 #include "sandbox/linux/seccomp-bpf/verifier.h"
9 9
10 // The kernel gives us a sandbox, we turn it into a playground :-) 10 // The kernel gives us a sandbox, we turn it into a playground :-)
11 // This is version 2 of the playground; version 1 was built on top of 11 // This is version 2 of the playground; version 1 was built on top of
12 // pre-BPF seccomp mode. 12 // pre-BPF seccomp mode.
13 namespace playground2 { 13 namespace playground2 {
14 14
15 // We define a really simple sandbox policy. It is just good enough for us 15 // We define a really simple sandbox policy. It is just good enough for us
16 // to tell that the sandbox has actually been activated. 16 // to tell that the sandbox has actually been activated.
17 Sandbox::ErrorCode Sandbox::probeEvaluator(int signo) { 17 ErrorCode Sandbox::probeEvaluator(int signo) {
18 switch (signo) { 18 switch (signo) {
19 case __NR_getpid: 19 case __NR_getpid:
20 // Return EPERM so that we can check that the filter actually ran. 20 // Return EPERM so that we can check that the filter actually ran.
21 return EPERM; 21 return ErrorCode(EPERM);
22 case __NR_exit_group: 22 case __NR_exit_group:
23 // Allow exit() with a non-default return code. 23 // Allow exit() with a non-default return code.
24 return SB_ALLOWED; 24 return ErrorCode(ErrorCode::ERR_ALLOWED);
25 default: 25 default:
26 // Make everything else fail in an easily recognizable way. 26 // Make everything else fail in an easily recognizable way.
27 return EINVAL; 27 return ErrorCode(EINVAL);
28 } 28 }
29 } 29 }
30 30
31 void Sandbox::probeProcess(void) { 31 void Sandbox::probeProcess(void) {
32 if (syscall(__NR_getpid) < 0 && errno == EPERM) { 32 if (syscall(__NR_getpid) < 0 && errno == EPERM) {
33 syscall(__NR_exit_group, (intptr_t)100); 33 syscall(__NR_exit_group, (intptr_t)100);
34 } 34 }
35 } 35 }
36 36
37 Sandbox::ErrorCode Sandbox::allowAllEvaluator(int signo) { 37 ErrorCode Sandbox::allowAllEvaluator(int signo) {
38 if (signo < static_cast<int>(MIN_SYSCALL) || 38 if (signo < static_cast<int>(MIN_SYSCALL) ||
39 signo > static_cast<int>(MAX_SYSCALL)) { 39 signo > static_cast<int>(MAX_SYSCALL)) {
40 return ENOSYS; 40 return ErrorCode(ENOSYS);
41 } 41 }
42 return Sandbox::SB_ALLOWED; 42 return ErrorCode(ErrorCode::ERR_ALLOWED);
43 } 43 }
44 44
45 void Sandbox::tryVsyscallProcess(void) { 45 void Sandbox::tryVsyscallProcess(void) {
46 time_t current_time; 46 time_t current_time;
47 // time() is implemented as a vsyscall. With an older glibc, with 47 // time() is implemented as a vsyscall. With an older glibc, with
48 // vsyscall=emulate and some versions of the seccomp BPF patch 48 // vsyscall=emulate and some versions of the seccomp BPF patch
49 // we may get SIGKILL-ed. Detect this! 49 // we may get SIGKILL-ed. Detect this!
50 if (time(&current_time) != static_cast<time_t>(-1)) { 50 if (time(&current_time) != static_cast<time_t>(-1)) {
51 syscall(__NR_exit_group, (intptr_t)100); 51 syscall(__NR_exit_group, (intptr_t)100);
52 } 52 }
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 } 136 }
137 if (HANDLE_EINTR(close(fds[0]))) { 137 if (HANDLE_EINTR(close(fds[0]))) {
138 SANDBOX_DIE("close() failed"); 138 SANDBOX_DIE("close() failed");
139 } 139 }
140 140
141 return rc; 141 return rc;
142 142
143 } 143 }
144 144
145 bool Sandbox::kernelSupportSeccompBPF(int proc_fd) { 145 bool Sandbox::kernelSupportSeccompBPF(int proc_fd) {
146 #if defined(SECCOMP_BPF_VALGRIND_HACKS)
147 if (RUNNING_ON_VALGRIND) {
148 // Valgrind doesn't like our run-time test. Disable testing and assume we
149 // always support sandboxing. This feature should only ever be enabled when
150 // debugging.
151 return true;
152 }
153 #endif
154
146 return RunFunctionInPolicy(probeProcess, Sandbox::probeEvaluator, proc_fd) && 155 return RunFunctionInPolicy(probeProcess, Sandbox::probeEvaluator, proc_fd) &&
147 RunFunctionInPolicy(tryVsyscallProcess, Sandbox::allowAllEvaluator, 156 RunFunctionInPolicy(tryVsyscallProcess, Sandbox::allowAllEvaluator,
148 proc_fd); 157 proc_fd);
149 } 158 }
150 159
151 Sandbox::SandboxStatus Sandbox::supportsSeccompSandbox(int proc_fd) { 160 Sandbox::SandboxStatus Sandbox::supportsSeccompSandbox(int proc_fd) {
152 // It the sandbox is currently active, we clearly must have support for 161 // It the sandbox is currently active, we clearly must have support for
153 // sandboxing. 162 // sandboxing.
154 if (status_ == STATUS_ENABLED) { 163 if (status_ == STATUS_ENABLED) {
155 return status_; 164 return status_;
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 sb.st_nlink != 3 || 257 sb.st_nlink != 3 ||
249 HANDLE_EINTR(close(task))) { 258 HANDLE_EINTR(close(task))) {
250 if (task >= 0) { 259 if (task >= 0) {
251 if (HANDLE_EINTR(close(task))) { } 260 if (HANDLE_EINTR(close(task))) { }
252 } 261 }
253 return false; 262 return false;
254 } 263 }
255 return true; 264 return true;
256 } 265 }
257 266
258 static bool isDenied(const Sandbox::ErrorCode& code) { 267 bool Sandbox::isDenied(const ErrorCode& code) {
259 return (code & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP || 268 return (code.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP ||
260 (code >= (SECCOMP_RET_ERRNO + 1) && 269 (code.err() >= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MIN_ERRNO) &&
261 code <= (SECCOMP_RET_ERRNO + 4095)); 270 code.err() <= (SECCOMP_RET_ERRNO + ErrorCode::ERR_MAX_ERRNO));
262 } 271 }
263 272
264 void Sandbox::policySanityChecks(EvaluateSyscall syscallEvaluator, 273 void Sandbox::policySanityChecks(EvaluateSyscall syscallEvaluator,
265 EvaluateArguments) { 274 EvaluateArguments) {
266 // Do some sanity checks on the policy. This will warn users if they do 275 // Do some sanity checks on the policy. This will warn users if they do
267 // things that are likely unsafe and unintended. 276 // things that are likely unsafe and unintended.
268 // We also have similar checks later, when we actually compile the BPF 277 // We also have similar checks later, when we actually compile the BPF
269 // program. That catches problems with incorrectly stacked evaluators. 278 // program. That catches problems with incorrectly stacked evaluators.
270 if (!isDenied(syscallEvaluator(-1))) { 279 if (!isDenied(syscallEvaluator(-1))) {
271 SANDBOX_DIE("Negative system calls should always be disallowed by policy"); 280 SANDBOX_DIE("Negative system calls should always be disallowed by policy");
272 } 281 }
273 #ifndef NDEBUG 282 #ifndef NDEBUG
274 #if defined(__i386__) || defined(__x86_64__) 283 #if defined(__i386__) || defined(__x86_64__)
275 #if defined(__x86_64__) && defined(__ILP32__) 284 #if defined(__x86_64__) && defined(__ILP32__)
276 for (unsigned int sysnum = MIN_SYSCALL & ~0x40000000u; 285 for (unsigned int sysnum = MIN_SYSCALL & ~0x40000000u;
277 sysnum <= (MAX_SYSCALL & ~0x40000000u); 286 sysnum <= (MAX_SYSCALL & ~0x40000000u);
278 ++sysnum) { 287 ++sysnum) {
279 if (!isDenied(syscallEvaluator(sysnum))) { 288 if (!isDenied(syscallEvaluator(sysnum))) {
280 SANDBOX_DIE("In x32 mode, you should not allow any non-x32 system calls"); 289 SANDBOX_DIE("In x32 mode, you should not allow any non-x32 "
290 "system calls");
281 } 291 }
282 } 292 }
283 #else 293 #else
284 for (unsigned int sysnum = MIN_SYSCALL | 0x40000000u; 294 for (unsigned int sysnum = MIN_SYSCALL | 0x40000000u;
285 sysnum <= (MAX_SYSCALL | 0x40000000u); 295 sysnum <= (MAX_SYSCALL | 0x40000000u);
286 ++sysnum) { 296 ++sysnum) {
287 if (!isDenied(syscallEvaluator(sysnum))) { 297 if (!isDenied(syscallEvaluator(sysnum))) {
288 SANDBOX_DIE("x32 system calls should be explicitly disallowed"); 298 SANDBOX_DIE("x32 system calls should be explicitly disallowed");
289 } 299 }
290 } 300 }
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 362
353 // If the architecture doesn't match SECCOMP_ARCH, disallow the 363 // If the architecture doesn't match SECCOMP_ARCH, disallow the
354 // system call. 364 // system call.
355 program->push_back((struct sock_filter) 365 program->push_back((struct sock_filter)
356 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, arch))); 366 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, arch)));
357 program->push_back((struct sock_filter) 367 program->push_back((struct sock_filter)
358 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_ARCH, 1, 0)); 368 BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_ARCH, 1, 0));
359 369
360 program->push_back((struct sock_filter) 370 program->push_back((struct sock_filter)
361 BPF_STMT(BPF_RET+BPF_K, 371 BPF_STMT(BPF_RET+BPF_K,
362 ErrorCode(bpfFailure, 372 Kill("Invalid audit architecture in BPF filter").err()));
363 "Invalid audit architecture in BPF filter")));
364 373
365 // Grab the system call number, so that we can implement jump tables. 374 // Grab the system call number, so that we can implement jump tables.
366 program->push_back((struct sock_filter) 375 program->push_back((struct sock_filter)
367 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, nr))); 376 BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct arch_seccomp_data, nr)));
368 377
369 // On Intel architectures, verify that system call numbers are in the 378 // On Intel architectures, verify that system call numbers are in the
370 // expected number range. The older i386 and x86-64 APIs clear bit 30 379 // expected number range. The older i386 and x86-64 APIs clear bit 30
371 // on all system calls. The newer x86-32 API always sets bit 30. 380 // on all system calls. The newer x86-32 API always sets bit 30.
372 #if defined(__i386__) || defined(__x86_64__) 381 #if defined(__i386__) || defined(__x86_64__)
373 #if defined(__x86_64__) && defined(__ILP32__) 382 #if defined(__x86_64__) && defined(__ILP32__)
374 program->push_back((struct sock_filter) 383 program->push_back((struct sock_filter)
375 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 1, 0)); 384 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 1, 0));
376 #else 385 #else
377 program->push_back((struct sock_filter) 386 program->push_back((struct sock_filter)
378 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 0, 1)); 387 BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 0, 1));
379 #endif 388 #endif
380 program->push_back((struct sock_filter) 389 program->push_back((struct sock_filter)
381 BPF_STMT(BPF_RET+BPF_K, 390 BPF_STMT(BPF_RET+BPF_K,
382 ErrorCode(bpfFailure, 391 Kill("Illegal mixing of system call ABIs").err()));
383 "Illegal mixing of system call ABIs")));
384 #endif 392 #endif
385 393
386 394
387 { 395 {
388 // Evaluate all possible system calls and group their ErrorCodes into 396 // Evaluate all possible system calls and group their ErrorCodes into
389 // ranges of identical codes. 397 // ranges of identical codes.
390 Ranges ranges; 398 Ranges ranges;
391 findRanges(&ranges); 399 findRanges(&ranges);
392 400
393 // Compile the system call ranges to an optimized BPF program 401 // Compile the system call ranges to an optimized BPF program
(...skipping 24 matching lines...) Expand all
418 // system memory allocator that is in effect, these operators can result 426 // system memory allocator that is in effect, these operators can result
419 // in system calls to things like munmap() or brk(). 427 // in system calls to things like munmap() or brk().
420 struct sock_filter bpf[program->size()]; 428 struct sock_filter bpf[program->size()];
421 const struct sock_fprog prog = { 429 const struct sock_fprog prog = {
422 static_cast<unsigned short>(program->size()), bpf }; 430 static_cast<unsigned short>(program->size()), bpf };
423 memcpy(bpf, &(*program)[0], sizeof(bpf)); 431 memcpy(bpf, &(*program)[0], sizeof(bpf));
424 delete program; 432 delete program;
425 433
426 // Release memory that is no longer needed 434 // Release memory that is no longer needed
427 evaluators_.clear(); 435 evaluators_.clear();
436 errMap_.clear();
428 437
429 // Install BPF filter program 438 #if defined(SECCOMP_BPF_VALGRIND_HACKS)
430 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 439 // Valgrind is really not happy about our sandbox. Disable it when running
431 SANDBOX_DIE(quiet 440 // in Valgrind. This feature is dangerous and should never be enabled by
432 ? NULL : "Kernel refuses to enable no-new-privs"); 441 // default. We protect it behind a pre-processor option.
433 } else { 442 if (!RUNNING_ON_VALGRIND)
434 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { 443 #endif
435 SANDBOX_DIE(quiet 444 {
436 ? NULL : "Kernel refuses to turn on BPF filters"); 445 // Install BPF filter program
446 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
447 SANDBOX_DIE(quiet ? NULL : "Kernel refuses to enable no-new-privs");
448 } else {
449 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
450 SANDBOX_DIE(quiet ? NULL : "Kernel refuses to turn on BPF filters");
451 }
437 } 452 }
438 } 453 }
439 454
440 return; 455 return;
441 } 456 }
442 457
443 void Sandbox::findRanges(Ranges *ranges) { 458 void Sandbox::findRanges(Ranges *ranges) {
444 // Please note that "struct seccomp_data" defines system calls as a signed 459 // Please note that "struct seccomp_data" defines system calls as a signed
445 // int32_t, but BPF instructions always operate on unsigned quantities. We 460 // int32_t, but BPF instructions always operate on unsigned quantities. We
446 // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL, 461 // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL,
447 // and then verifying that the rest of the number range (both positive and 462 // and then verifying that the rest of the number range (both positive and
448 // negative) all return the same ErrorCode. 463 // negative) all return the same ErrorCode.
449 EvaluateSyscall evaluateSyscall = evaluators_.begin()->first; 464 EvaluateSyscall evaluateSyscall = evaluators_.begin()->first;
450 uint32_t oldSysnum = 0; 465 uint32_t oldSysnum = 0;
451 ErrorCode oldErr = evaluateSyscall(oldSysnum); 466 ErrorCode oldErr = evaluateSyscall(oldSysnum);
452 for (uint32_t sysnum = std::max(1u, MIN_SYSCALL); 467 for (uint32_t sysnum = std::max(1u, MIN_SYSCALL);
453 sysnum <= MAX_SYSCALL + 1; 468 sysnum <= MAX_SYSCALL + 1;
454 ++sysnum) { 469 ++sysnum) {
455 ErrorCode err = evaluateSyscall(static_cast<int>(sysnum)); 470 ErrorCode err = evaluateSyscall(static_cast<int>(sysnum));
456 if (err != oldErr) { 471 if (!err.Equals(oldErr)) {
457 ranges->push_back(Range(oldSysnum, sysnum-1, oldErr)); 472 ranges->push_back(Range(oldSysnum, sysnum-1, oldErr));
458 oldSysnum = sysnum; 473 oldSysnum = sysnum;
459 oldErr = err; 474 oldErr = err;
460 } 475 }
461 } 476 }
462 477
463 // As we looped all the way past the valid system calls (i.e. MAX_SYSCALL+1), 478 // As we looped all the way past the valid system calls (i.e. MAX_SYSCALL+1),
464 // "oldErr" should at this point be the "default" policy for all system call 479 // "oldErr" should at this point be the "default" policy for all system call
465 // numbers that don't have an explicit handler in the system call evaluator. 480 // numbers that don't have an explicit handler in the system call evaluator.
466 // But as we are quite paranoid, we perform some more sanity checks to verify 481 // But as we are quite paranoid, we perform some more sanity checks to verify
467 // that there actually is a consistent "default" policy in the first place. 482 // that there actually is a consistent "default" policy in the first place.
468 // We don't actually iterate over all possible 2^32 values, though. We just 483 // We don't actually iterate over all possible 2^32 values, though. We just
469 // perform spot checks at the boundaries. 484 // perform spot checks at the boundaries.
470 // The cases that we test are: 0x7FFFFFFF, 0x80000000, 0xFFFFFFFF. 485 // The cases that we test are: 0x7FFFFFFF, 0x80000000, 0xFFFFFFFF.
471 if (oldErr != evaluateSyscall(std::numeric_limits<int>::max()) || 486 if (!oldErr.Equals(evaluateSyscall(std::numeric_limits<int>::max())) ||
472 oldErr != evaluateSyscall(std::numeric_limits<int>::min()) || 487 !oldErr.Equals(evaluateSyscall(std::numeric_limits<int>::min())) ||
473 oldErr != evaluateSyscall(-1)) { 488 !oldErr.Equals(evaluateSyscall(-1))) {
474 SANDBOX_DIE("Invalid seccomp policy"); 489 SANDBOX_DIE("Invalid seccomp policy");
475 } 490 }
476 ranges->push_back( 491 ranges->push_back(
477 Range(oldSysnum, std::numeric_limits<unsigned>::max(), oldErr)); 492 Range(oldSysnum, std::numeric_limits<unsigned>::max(), oldErr));
478 } 493 }
479 494
480 void Sandbox::emitJumpStatements(Program *program, RetInsns *rets, 495 void Sandbox::emitJumpStatements(Program *program, RetInsns *rets,
481 Ranges::const_iterator start, 496 Ranges::const_iterator start,
482 Ranges::const_iterator stop) { 497 Ranges::const_iterator stop) {
483 // We convert the list of system call ranges into jump table that performs 498 // We convert the list of system call ranges into jump table that performs
(...skipping 23 matching lines...) Expand all
507 // less than the range object at the mid point of the list. 522 // less than the range object at the mid point of the list.
508 if (mid - start == 1) { 523 if (mid - start == 1) {
509 // If we have narrowed things down to a single range object, we can 524 // If we have narrowed things down to a single range object, we can
510 // return from the BPF filter program. 525 // return from the BPF filter program.
511 // Instead of emitting a BPF_RET statement, we want to coalesce all 526 // Instead of emitting a BPF_RET statement, we want to coalesce all
512 // identical BPF_RET statements into a single instance. This results in 527 // identical BPF_RET statements into a single instance. This results in
513 // a more efficient BPF program that uses less CPU cache. 528 // a more efficient BPF program that uses less CPU cache.
514 // Since all branches in BPF programs have to be forward branches, we 529 // Since all branches in BPF programs have to be forward branches, we
515 // keep track of our current instruction pointer and then fix up the 530 // keep track of our current instruction pointer and then fix up the
516 // branch when we emit the BPF_RET statement in emitReturnStatements(). 531 // branch when we emit the BPF_RET statement in emitReturnStatements().
517 (*rets)[start->err].push_back(FixUp(jmp, false)); 532 (*rets)[start->err.err()].push_back(FixUp(jmp, false));
518 } else { 533 } else {
519 // Sub-divide the list of ranges and continue recursively. 534 // Sub-divide the list of ranges and continue recursively.
520 emitJumpStatements(program, rets, start, mid); 535 emitJumpStatements(program, rets, start, mid);
521 } 536 }
522 537
523 // The comparison turned out to be true; i.e. our system call number is 538 // The comparison turned out to be true; i.e. our system call number is
524 // greater or equal to the range object at the mid point of the list. 539 // greater or equal to the range object at the mid point of the list.
525 if (stop - mid == 1) { 540 if (stop - mid == 1) {
526 // We narrowed things down to a single range object. Remember instruction 541 // We narrowed things down to a single range object. Remember instruction
527 // pointer and exit code, so that we can patch up the target of the jump 542 // pointer and exit code, so that we can patch up the target of the jump
528 // instruction in emitReturnStatements(). 543 // instruction in emitReturnStatements().
529 (*rets)[mid->err].push_back(FixUp(jmp, true)); 544 (*rets)[mid->err.err()].push_back(FixUp(jmp, true));
530 } else { 545 } else {
531 // We now know where the block of instructions for the "true" comparison 546 // We now know where the block of instructions for the "true" comparison
532 // starts. Patch up the jump target of the BPF_JMP instruction that we 547 // starts. Patch up the jump target of the BPF_JMP instruction that we
533 // emitted earlier. 548 // emitted earlier.
534 int distance = program->size() - jmp - 1; 549 int distance = program->size() - jmp - 1;
535 if (distance < 0 || distance > 255) { 550 if (distance < 0 || distance > 255) {
536 goto compiler_err; 551 goto compiler_err;
537 } 552 }
538 (*program)[jmp].jt = distance; 553 (*program)[jmp].jt = distance;
539 554
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 } 592 }
578 } 593 }
579 594
580 void Sandbox::sigSys(int nr, siginfo_t *info, void *void_context) { 595 void Sandbox::sigSys(int nr, siginfo_t *info, void *void_context) {
581 // Various sanity checks to make sure we actually received a signal 596 // Various sanity checks to make sure we actually received a signal
582 // triggered by a BPF filter. If something else triggered SIGSYS 597 // triggered by a BPF filter. If something else triggered SIGSYS
583 // (e.g. kill()), there is really nothing we can do with this signal. 598 // (e.g. kill()), there is really nothing we can do with this signal.
584 if (nr != SIGSYS || info->si_code != SYS_SECCOMP || !void_context || 599 if (nr != SIGSYS || info->si_code != SYS_SECCOMP || !void_context ||
585 info->si_errno <= 0 || 600 info->si_errno <= 0 ||
586 static_cast<size_t>(info->si_errno) > trapArraySize_) { 601 static_cast<size_t>(info->si_errno) > trapArraySize_) {
587 // SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal safe 602 // SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal
588 // and can lead to bugs. We should eventually implement a different 603 // safe and can lead to bugs. We should eventually implement a different
589 // logging and reporting mechanism that is safe to be called from 604 // logging and reporting mechanism that is safe to be called from
590 // the sigSys() handler. 605 // the sigSys() handler.
591 // TODO: If we feel confident that our code otherwise works correctly, we 606 // TODO: If we feel confident that our code otherwise works correctly, we
592 // could actually make an argument that spurious SIGSYS should 607 // could actually make an argument that spurious SIGSYS should
593 // just get silently ignored. TBD 608 // just get silently ignored. TBD
594 sigsys_err: 609 sigsys_err:
595 SANDBOX_DIE("Unexpected SIGSYS received"); 610 SANDBOX_DIE("Unexpected SIGSYS received");
596 } 611 }
597 612
598 // Signal handlers should always preserve "errno". Otherwise, we could 613 // Signal handlers should always preserve "errno". Otherwise, we could
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
640 655
641 // Update the CPU register that stores the return code of the system call 656 // Update the CPU register that stores the return code of the system call
642 // that we just handled, and restore "errno" to the value that it had 657 // that we just handled, and restore "errno" to the value that it had
643 // before entering the signal handler. 658 // before entering the signal handler.
644 SECCOMP_RESULT(ctx) = static_cast<greg_t>(rc); 659 SECCOMP_RESULT(ctx) = static_cast<greg_t>(rc);
645 errno = old_errno; 660 errno = old_errno;
646 661
647 return; 662 return;
648 } 663 }
649 664
650 intptr_t Sandbox::bpfFailure(const struct arch_seccomp_data&, void *aux) { 665 ErrorCode Sandbox::Trap(ErrorCode::TrapFnc fnc, const void *aux) {
651 SANDBOX_DIE(static_cast<char *>(aux));
652 }
653
654 int Sandbox::getTrapId(Sandbox::TrapFnc fnc, const void *aux) {
655 // Each unique pair of TrapFnc and auxiliary data make up a distinct instance 666 // Each unique pair of TrapFnc and auxiliary data make up a distinct instance
656 // of a SECCOMP_RET_TRAP. 667 // of a SECCOMP_RET_TRAP.
657 std::pair<TrapFnc, const void *> key(fnc, aux); 668 std::pair<ErrorCode::TrapFnc, const void *> key(fnc, aux);
658 TrapIds::const_iterator iter = trapIds_.find(key); 669 TrapIds::const_iterator iter = trapIds_.find(key);
670 uint16_t id;
659 if (iter != trapIds_.end()) { 671 if (iter != trapIds_.end()) {
660 // We have seen this pair before. Return the same id that we assigned 672 // We have seen this pair before. Return the same id that we assigned
661 // earlier. 673 // earlier.
662 return iter->second; 674 id = iter->second;
663 } else { 675 } else {
664 // This is a new pair. Remember it and assign a new id. 676 // This is a new pair. Remember it and assign a new id.
665 // Please note that we have to store traps in memory that doesn't get 677 // Please note that we have to store traps in memory that doesn't get
666 // deallocated when the program is shutting down. A memory leak is 678 // deallocated when the program is shutting down. A memory leak is
667 // intentional, because we might otherwise not be able to execute 679 // intentional, because we might otherwise not be able to execute
668 // system calls part way through the program shutting down 680 // system calls part way through the program shutting down
669 if (!traps_) { 681 if (!traps_) {
670 traps_ = new Traps(); 682 traps_ = new Traps();
671 } 683 }
672 Traps::size_type id = traps_->size() + 1; 684 if (traps_->size() >= SECCOMP_RET_DATA) {
673 if (id > SECCOMP_RET_DATA) {
674 // In practice, this is pretty much impossible to trigger, as there 685 // In practice, this is pretty much impossible to trigger, as there
675 // are other kernel limitations that restrict overall BPF program sizes. 686 // are other kernel limitations that restrict overall BPF program sizes.
676 SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances"); 687 SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances");
677 } 688 }
689 id = traps_->size() + 1;
678 690
679 traps_->push_back(ErrorCode(fnc, aux, id)); 691 traps_->push_back(ErrorCode(fnc, aux, id));
680 trapIds_[key] = id; 692 trapIds_[key] = id;
681 693
682 // We want to access the traps_ vector from our signal handler. But 694 // We want to access the traps_ vector from our signal handler. But
683 // we are not assured that doing so is async-signal safe. On the other 695 // we are not assured that doing so is async-signal safe. On the other
684 // hand, C++ guarantees that the contents of a vector is stored in a 696 // hand, C++ guarantees that the contents of a vector is stored in a
685 // contiguous C-style array. 697 // contiguous C-style array.
686 // So, we look up the address and size of this array outside of the 698 // So, we look up the address and size of this array outside of the
687 // signal handler, where we can safely do so. 699 // signal handler, where we can safely do so.
688 trapArray_ = &(*traps_)[0]; 700 trapArray_ = &(*traps_)[0];
689 trapArraySize_ = id; 701 trapArraySize_ = id;
690 return id;
691 } 702 }
703
704 ErrorCode err = ErrorCode(fnc, aux, id);
705 return errMap_[err.err()] = err;
706 }
707
708 intptr_t Sandbox::bpfFailure(const struct arch_seccomp_data&, void *aux) {
709 SANDBOX_DIE(static_cast<char *>(aux));
710 }
711
712 ErrorCode Sandbox::Kill(const char *msg) {
713 return Trap(bpfFailure, const_cast<char *>(msg));
692 } 714 }
693 715
694 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; 716 Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN;
695 int Sandbox::proc_fd_ = -1; 717 int Sandbox::proc_fd_ = -1;
696 Sandbox::Evaluators Sandbox::evaluators_; 718 Sandbox::Evaluators Sandbox::evaluators_;
719 Sandbox::ErrMap Sandbox::errMap_;
697 Sandbox::Traps *Sandbox::traps_ = NULL; 720 Sandbox::Traps *Sandbox::traps_ = NULL;
698 Sandbox::TrapIds Sandbox::trapIds_; 721 Sandbox::TrapIds Sandbox::trapIds_;
699 Sandbox::ErrorCode *Sandbox::trapArray_ = NULL; 722 ErrorCode *Sandbox::trapArray_ = NULL;
700 size_t Sandbox::trapArraySize_ = 0; 723 size_t Sandbox::trapArraySize_ = 0;
701 724
702 } // namespace 725 } // namespace
OLDNEW
« no previous file with comments | « sandbox/linux/seccomp-bpf/sandbox_bpf.h ('k') | sandbox/linux/seccomp-bpf/sandbox_bpf_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698