| OLD | NEW |
| 1 #include "library.h" | 1 #include "library.h" |
| 2 #include "sandbox_impl.h" | 2 #include "sandbox_impl.h" |
| 3 #include "syscall_table.h" | 3 #include "syscall_table.h" |
| 4 | 4 |
| 5 namespace playground { | 5 namespace playground { |
| 6 | 6 |
| 7 // Global variables | 7 // Global variables |
| 8 int Sandbox::proc_self_maps_ = -1; |
| 8 enum Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; | 9 enum Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; |
| 9 int Sandbox::pid_; | 10 int Sandbox::pid_; |
| 10 int Sandbox::processFdPub_; | 11 int Sandbox::processFdPub_; |
| 11 int Sandbox::cloneFdPub_; | 12 int Sandbox::cloneFdPub_; |
| 12 Sandbox::ProtectedMap Sandbox::protectedMap_; | 13 Sandbox::ProtectedMap Sandbox::protectedMap_; |
| 13 std::vector<SecureMem::Args*> Sandbox::secureMemPool_; | 14 std::vector<SecureMem::Args*> Sandbox::secureMemPool_; |
| 14 | 15 |
| 15 bool Sandbox::sendFd(int transport, int fd0, int fd1, const void* buf, | 16 bool Sandbox::sendFd(int transport, int fd0, int fd1, const void* buf, |
| 16 size_t len) { | 17 size_t len) { |
| 17 int fds[2], count = 0; | 18 int fds[2], count = 0; |
| (...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 : "memory" | 334 : "memory" |
| 334 #if defined(__x86_64__) | 335 #if defined(__x86_64__) |
| 335 , "rsp" | 336 , "rsp" |
| 336 #elif defined(__i386__) | 337 #elif defined(__i386__) |
| 337 , "esp" | 338 , "esp" |
| 338 #endif | 339 #endif |
| 339 ); | 340 ); |
| 340 return fnc; | 341 return fnc; |
| 341 } | 342 } |
| 342 | 343 |
| 343 void Sandbox::snapshotMemoryMappings(int processFd) { | 344 void Sandbox::snapshotMemoryMappings(int processFd, int proc_self_maps) { |
| 344 SysCalls sys; | 345 SysCalls sys; |
| 345 int mapsFd = sys.open("/proc/self/maps", O_RDONLY, 0); | 346 if (sys.lseek(proc_self_maps, 0, SEEK_SET) || |
| 346 if (mapsFd < 0 || !sendFd(processFd, mapsFd, -1, NULL, 0)) { | 347 !sendFd(processFd, proc_self_maps, -1, NULL, 0)) { |
| 347 failure: | 348 failure: |
| 348 die("Cannot access /proc/self/maps"); | 349 die("Cannot access /proc/self/maps"); |
| 349 } | 350 } |
| 350 NOINTR_SYS(sys.close(mapsFd)); | |
| 351 int dummy; | 351 int dummy; |
| 352 if (read(sys, processFd, &dummy, sizeof(dummy)) != sizeof(dummy)) { | 352 if (read(sys, processFd, &dummy, sizeof(dummy)) != sizeof(dummy)) { |
| 353 goto failure; | 353 goto failure; |
| 354 } | 354 } |
| 355 } | 355 } |
| 356 | 356 |
| 357 int Sandbox::supportsSeccompSandbox() { | 357 int Sandbox::supportsSeccompSandbox(int proc_fd) { |
| 358 if (status_ != STATUS_UNKNOWN) { | 358 if (status_ != STATUS_UNKNOWN) { |
| 359 return status_ != STATUS_UNSUPPORTED; | 359 return status_ != STATUS_UNSUPPORTED; |
| 360 } | 360 } |
| 361 int fds[2]; | 361 int fds[2]; |
| 362 SysCalls sys; | 362 SysCalls sys; |
| 363 if (sys.pipe(fds)) { | 363 if (sys.pipe(fds)) { |
| 364 status_ = STATUS_UNSUPPORTED; | 364 status_ = STATUS_UNSUPPORTED; |
| 365 return 0; | 365 return 0; |
| 366 } | 366 } |
| 367 pid_t pid; | 367 pid_t pid; |
| 368 switch ((pid = sys.fork())) { | 368 switch ((pid = sys.fork())) { |
| 369 case -1: | 369 case -1: |
| 370 status_ = STATUS_UNSUPPORTED; | 370 status_ = STATUS_UNSUPPORTED; |
| 371 return 0; | 371 return 0; |
| 372 case 0: { | 372 case 0: { |
| 373 int devnull = sys.open("/dev/null", O_RDWR, 0); | 373 int devnull = sys.open("/dev/null", O_RDWR, 0); |
| 374 if (devnull >= 0) { | 374 if (devnull >= 0) { |
| 375 dup2(devnull, 0); | 375 dup2(devnull, 0); |
| 376 dup2(devnull, 1); | 376 dup2(devnull, 1); |
| 377 dup2(devnull, 2); | 377 dup2(devnull, 2); |
| 378 } | 378 } |
| 379 if (proc_fd >= 0) { |
| 380 setProcSelfMaps(sys.openat(proc_fd, "self/maps", O_RDONLY, 0)); |
| 381 } |
| 379 startSandbox(); | 382 startSandbox(); |
| 380 write(sys, fds[1], "", 1); | 383 write(sys, fds[1], "", 1); |
| 381 _exit(0); | 384 |
| 382 sys.exit_group(0); | 385 // Try to tell the trusted thread to shut down the entire process in an |
| 386 // orderly fashion |
| 387 defaultSystemCallHandler(__NR_exit_group, 0, 0, 0, 0, 0, 0); |
| 388 |
| 389 // If that did not work (e.g. because the kernel does not know about the |
| 390 // exit_group() system call), make a direct _exit() system call instead. |
| 391 // This system call is unrestricted in seccomp mode, so it will always |
| 392 // succeed. Normally, we don't like it, because unlike exit_group() it |
| 393 // does not terminate any other thread. But since we know that |
| 394 // exit_group() exists in all kernels which support kernel-level threads, |
| 395 // this is OK we only get here for old kernels where _exit() is OK. |
| 383 sys._exit(0); | 396 sys._exit(0); |
| 384 } | 397 } |
| 385 default: | 398 default: |
| 386 NOINTR_SYS(sys.close(fds[1])); | 399 NOINTR_SYS(sys.close(fds[1])); |
| 387 char ch; | 400 char ch; |
| 388 if (read(sys, fds[0], &ch, 1) != 1) { | 401 if (read(sys, fds[0], &ch, 1) != 1) { |
| 389 status_ = STATUS_UNSUPPORTED; | 402 status_ = STATUS_UNSUPPORTED; |
| 390 } else { | 403 } else { |
| 391 status_ = STATUS_AVAILABLE; | 404 status_ = STATUS_AVAILABLE; |
| 392 } | 405 } |
| 393 int rc; | 406 int rc; |
| 394 NOINTR_SYS(sys.waitpid(pid, &rc, 0)); | 407 NOINTR_SYS(sys.waitpid(pid, &rc, 0)); |
| 395 NOINTR_SYS(sys.close(fds[0])); | 408 NOINTR_SYS(sys.close(fds[0])); |
| 396 return status_ != STATUS_UNSUPPORTED; | 409 return status_ != STATUS_UNSUPPORTED; |
| 397 } | 410 } |
| 398 } | 411 } |
| 399 | 412 |
| 413 void Sandbox::setProcSelfMaps(int proc_self_maps) { |
| 414 proc_self_maps_ = proc_self_maps; |
| 415 } |
| 416 |
| 400 void Sandbox::startSandbox() { | 417 void Sandbox::startSandbox() { |
| 401 if (status_ == STATUS_UNSUPPORTED) { | 418 if (status_ == STATUS_UNSUPPORTED) { |
| 402 die("The seccomp sandbox is not supported on this computer"); | 419 die("The seccomp sandbox is not supported on this computer"); |
| 403 } else if (status_ == STATUS_ENABLED) { | 420 } else if (status_ == STATUS_ENABLED) { |
| 404 return; | 421 return; |
| 405 } | 422 } |
| 406 | 423 |
| 407 SysCalls sys; | 424 SysCalls sys; |
| 425 if (proc_self_maps_ < 0) { |
| 426 proc_self_maps_ = sys.open("/proc/self/maps", O_RDONLY, 0); |
| 427 if (proc_self_maps_ < 0) { |
| 428 die("Cannot access \"/proc/self/maps\""); |
| 429 } |
| 430 } |
| 408 | 431 |
| 409 // The pid is unchanged for the entire program, so we can retrieve it once | 432 // The pid is unchanged for the entire program, so we can retrieve it once |
| 410 // and store it in a global variable. | 433 // and store it in a global variable. |
| 411 pid_ = sys.getpid(); | 434 pid_ = sys.getpid(); |
| 412 | 435 |
| 413 // Block all signals, except for the RDTSC handler | 436 // Block all signals, except for the RDTSC handler |
| 414 setupSignalHandlers(); | 437 setupSignalHandlers(); |
| 415 | 438 |
| 416 // Get socketpairs for talking to the trusted process | 439 // Get socketpairs for talking to the trusted process |
| 417 int pair[4]; | 440 int pair[4]; |
| 418 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) || | 441 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) || |
| 419 socketpair(AF_UNIX, SOCK_STREAM, 0, pair+2)) { | 442 socketpair(AF_UNIX, SOCK_STREAM, 0, pair+2)) { |
| 420 die("Failed to create trusted thread"); | 443 die("Failed to create trusted thread"); |
| 421 } | 444 } |
| 422 processFdPub_ = pair[0]; | 445 processFdPub_ = pair[0]; |
| 423 cloneFdPub_ = pair[2]; | 446 cloneFdPub_ = pair[2]; |
| 424 SecureMemArgs::Args* secureMem = createTrustedProcess(pair[0], pair[1], | 447 SecureMemArgs::Args* secureMem = createTrustedProcess(pair[0], pair[1], |
| 425 pair[2], pair[3]); | 448 pair[2], pair[3]); |
| 426 | 449 |
| 427 // We find all libraries that have system calls and redirect the system | 450 // We find all libraries that have system calls and redirect the system |
| 428 // calls to the sandbox. If we miss any system calls, the application will be | 451 // calls to the sandbox. If we miss any system calls, the application will be |
| 429 // terminated by the kernel's seccomp code. So, from a security point of | 452 // terminated by the kernel's seccomp code. So, from a security point of |
| 430 // view, if this code fails to identify system calls, we are still behaving | 453 // view, if this code fails to identify system calls, we are still behaving |
| 431 // correctly. | 454 // correctly. |
| 432 { | 455 { |
| 433 Maps maps("/proc/self/maps"); | 456 Maps maps(proc_self_maps_); |
| 434 const char *libs[] = { "ld", "libc", "librt", "libpthread", NULL }; | 457 const char *libs[] = { "ld", "libc", "librt", "libpthread", NULL }; |
| 435 | 458 |
| 436 // Intercept system calls in the VDSO segment (if any). This has to happen | 459 // Intercept system calls in the VDSO segment (if any). This has to happen |
| 437 // before intercepting system calls in any of the other libraries, as | 460 // before intercepting system calls in any of the other libraries, as |
| 438 // the main kernel entry point might be inside of the VDSO and we need to | 461 // the main kernel entry point might be inside of the VDSO and we need to |
| 439 // determine its address before we can compare it to jumps from inside | 462 // determine its address before we can compare it to jumps from inside |
| 440 // other libraries. | 463 // other libraries. |
| 441 for (Maps::const_iterator iter = maps.begin(); iter != maps.end(); ++iter){ | 464 for (Maps::const_iterator iter = maps.begin(); iter != maps.end(); ++iter){ |
| 442 Library* library = *iter; | 465 Library* library = *iter; |
| 443 if (library->isVDSO() && library->parseElf()) { | 466 if (library->isVDSO() && library->parseElf()) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 463 break; | 486 break; |
| 464 } | 487 } |
| 465 } | 488 } |
| 466 } | 489 } |
| 467 } | 490 } |
| 468 } | 491 } |
| 469 } | 492 } |
| 470 | 493 |
| 471 // Take a snapshot of the current memory mappings. These mappings will be | 494 // Take a snapshot of the current memory mappings. These mappings will be |
| 472 // off-limits to all future mmap(), munmap(), mremap(), and mprotect() calls. | 495 // off-limits to all future mmap(), munmap(), mremap(), and mprotect() calls. |
| 473 snapshotMemoryMappings(processFdPub_); | 496 snapshotMemoryMappings(processFdPub_, proc_self_maps_); |
| 497 NOINTR_SYS(sys.close(proc_self_maps_)); |
| 498 proc_self_maps_ = -1; |
| 474 | 499 |
| 475 // Creating the trusted thread enables sandboxing | 500 // Creating the trusted thread enables sandboxing |
| 476 createTrustedThread(processFdPub_, cloneFdPub_, secureMem); | 501 createTrustedThread(processFdPub_, cloneFdPub_, secureMem); |
| 477 | 502 |
| 478 // We can no longer check for sandboxing support at this point, but we also | 503 // We can no longer check for sandboxing support at this point, but we also |
| 479 // know for a fact that it is available (as we just turned it on). So update | 504 // know for a fact that it is available (as we just turned it on). So update |
| 480 // the status to reflect this information. | 505 // the status to reflect this information. |
| 481 status_ = STATUS_ENABLED; | 506 status_ = STATUS_ENABLED; |
| 482 } | 507 } |
| 483 | 508 |
| 484 } // namespace | 509 } // namespace |
| OLD | NEW |