diff options
author | markus@chromium.org <markus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-07 06:09:38 +0000 |
---|---|---|
committer | markus@chromium.org <markus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-07 06:09:38 +0000 |
commit | a9c54a176540e3a8173d72a1794cac3855bc9ce0 (patch) | |
tree | 7d316f2558c7e4f923d0c97ef45c4ed08b59cb45 /sandbox | |
parent | 282f4d24b40587c701ede40b014035ceffc9a3ea (diff) | |
download | chromium_src-a9c54a176540e3a8173d72a1794cac3855bc9ce0.zip chromium_src-a9c54a176540e3a8173d72a1794cac3855bc9ce0.tar.gz chromium_src-a9c54a176540e3a8173d72a1794cac3855bc9ce0.tar.bz2 |
Allow the seccomp sandbox to be enabled, even if the suid sandbox has
already put a chroot() jail around it. The only tricky part is access
to /proc/self/maps, but we can safely pass in an open file descriptor.
BUG=26527
Review URL: http://codereview.chromium.org/371047
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31372 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox')
-rw-r--r-- | sandbox/linux/seccomp/access.cc | 6 | ||||
-rw-r--r-- | sandbox/linux/seccomp/clone.cc | 8 | ||||
-rw-r--r-- | sandbox/linux/seccomp/exit.cc | 7 | ||||
-rw-r--r-- | sandbox/linux/seccomp/ioctl.cc | 2 | ||||
-rw-r--r-- | sandbox/linux/seccomp/ipc.cc | 10 | ||||
-rw-r--r-- | sandbox/linux/seccomp/madvise.cc | 2 | ||||
-rw-r--r-- | sandbox/linux/seccomp/maps.cc | 19 | ||||
-rw-r--r-- | sandbox/linux/seccomp/maps.h | 12 | ||||
-rw-r--r-- | sandbox/linux/seccomp/mmap.cc | 2 | ||||
-rw-r--r-- | sandbox/linux/seccomp/mprotect.cc | 5 | ||||
-rw-r--r-- | sandbox/linux/seccomp/munmap.cc | 2 | ||||
-rw-r--r-- | sandbox/linux/seccomp/open.cc | 6 | ||||
-rw-r--r-- | sandbox/linux/seccomp/sandbox.cc | 43 | ||||
-rw-r--r-- | sandbox/linux/seccomp/sandbox.h | 3 | ||||
-rw-r--r-- | sandbox/linux/seccomp/sandbox_impl.h | 25 | ||||
-rw-r--r-- | sandbox/linux/seccomp/securemem.cc | 26 | ||||
-rw-r--r-- | sandbox/linux/seccomp/socketcall.cc | 29 | ||||
-rw-r--r-- | sandbox/linux/seccomp/stat.cc | 6 | ||||
-rw-r--r-- | sandbox/linux/seccomp/syscall_table.h | 2 | ||||
-rw-r--r-- | sandbox/linux/seccomp/trusted_process.cc | 29 |
20 files changed, 141 insertions, 103 deletions
diff --git a/sandbox/linux/seccomp/access.cc b/sandbox/linux/seccomp/access.cc index 0a0d0e5..9e79d12 100644 --- a/sandbox/linux/seccomp/access.cc +++ b/sandbox/linux/seccomp/access.cc @@ -29,7 +29,7 @@ int Sandbox::sandbox_access(const char *pathname, int mode) { return static_cast<int>(rc); } -bool Sandbox::process_access(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_access(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request SysCalls sys; @@ -56,7 +56,7 @@ bool Sandbox::process_access(int parentProc, int sandboxFd, int threadFdPub, } return false; } - SecureMem::lockSystemCall(parentProc, mem); + SecureMem::lockSystemCall(parentMapsFd, mem); if (read(sys, sandboxFd, mem->pathname, access_req.path_length) != (ssize_t)access_req.path_length) { goto read_parm_failed; @@ -68,7 +68,7 @@ bool Sandbox::process_access(int parentProc, int sandboxFd, int threadFdPub, "\"").c_str()); // Tell trusted thread to access the file. - SecureMem::sendSystemCall(threadFdPub, true, parentProc, mem, __NR_access, + SecureMem::sendSystemCall(threadFdPub, true, parentMapsFd, mem, __NR_access, mem->pathname - (char*)mem + (char*)mem->self, access_req.mode); return true; diff --git a/sandbox/linux/seccomp/clone.cc b/sandbox/linux/seccomp/clone.cc index 109e5c6..2b6703f 100644 --- a/sandbox/linux/seccomp/clone.cc +++ b/sandbox/linux/seccomp/clone.cc @@ -42,7 +42,7 @@ int Sandbox::sandbox_clone(int flags, void* stack, int* pid, int* ctid, return static_cast<int>(rc); } -bool Sandbox::process_clone(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_clone(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request Clone clone_req; @@ -66,7 +66,7 @@ bool Sandbox::process_clone(int parentProc, int sandboxFd, int threadFdPub, // clone() has unusual semantics. We don't want to return back into the // trusted thread, but instead we need to continue execution at the IP // where we got called initially. - SecureMem::lockSystemCall(parentProc, mem); + SecureMem::lockSystemCall(parentMapsFd, mem); mem->ret = clone_req.ret; #if defined(__x86_64__) mem->rbp = clone_req.regs64.rbp; @@ -100,8 +100,8 @@ bool Sandbox::process_clone(int parentProc, int sandboxFd, int threadFdPub, mem->processFdPub = processFdPub_; mem->cloneFdPub = cloneFdPub_; - SecureMem::sendSystemCall(threadFdPub, true, parentProc, mem, __NR_clone, - clone_req.flags, clone_req.stack, + SecureMem::sendSystemCall(threadFdPub, true, parentMapsFd, mem, + __NR_clone, clone_req.flags, clone_req.stack, clone_req.pid, clone_req.ctid, clone_req.tls); return true; } diff --git a/sandbox/linux/seccomp/exit.cc b/sandbox/linux/seccomp/exit.cc index 23ebc55..4cf274a 100644 --- a/sandbox/linux/seccomp/exit.cc +++ b/sandbox/linux/seccomp/exit.cc @@ -22,10 +22,11 @@ int Sandbox::sandbox_exit(int status) { } } -bool Sandbox::process_exit(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_exit(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { - SecureMem::lockSystemCall(parentProc, mem); - SecureMem::sendSystemCall(threadFdPub, true, parentProc, mem, __NR_exit, 0); + SecureMem::lockSystemCall(parentMapsFd, mem); + SecureMem::sendSystemCall(threadFdPub, true, parentMapsFd, mem, + __NR_exit, 0); return true; } diff --git a/sandbox/linux/seccomp/ioctl.cc b/sandbox/linux/seccomp/ioctl.cc index ac630a7..46e5a8f 100644 --- a/sandbox/linux/seccomp/ioctl.cc +++ b/sandbox/linux/seccomp/ioctl.cc @@ -26,7 +26,7 @@ int Sandbox::sandbox_ioctl(int d, int req, void *arg) { return static_cast<int>(rc); } -bool Sandbox::process_ioctl(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_ioctl(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request IOCtl ioctl_req; diff --git a/sandbox/linux/seccomp/ipc.cc b/sandbox/linux/seccomp/ipc.cc index f3ad9a2..91b2ab7 100644 --- a/sandbox/linux/seccomp/ipc.cc +++ b/sandbox/linux/seccomp/ipc.cc @@ -108,7 +108,7 @@ int Sandbox::sandbox_shmget(int key, size_t size, int shmflg) { return static_cast<int>(rc); } -bool Sandbox::process_shmat(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_shmat(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request ShmAt shmat_req; @@ -133,7 +133,7 @@ bool Sandbox::process_shmat(int parentProc, int sandboxFd, int threadFdPub, return true; } -bool Sandbox::process_shmctl(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_shmctl(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request ShmCtl shmctl_req; @@ -158,7 +158,7 @@ bool Sandbox::process_shmctl(int parentProc, int sandboxFd, int threadFdPub, return true; } -bool Sandbox::process_shmdt(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_shmdt(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request ShmDt shmdt_req; @@ -193,7 +193,7 @@ bool Sandbox::process_shmdt(int parentProc, int sandboxFd, int threadFdPub, return true; } -bool Sandbox::process_shmget(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_shmget(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request ShmGet shmget_req; @@ -261,7 +261,7 @@ int Sandbox::sandbox_ipc(unsigned call, int first, int second, int third, return static_cast<int>(rc); } -bool Sandbox::process_ipc(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_ipc(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request IPC ipc_req; diff --git a/sandbox/linux/seccomp/madvise.cc b/sandbox/linux/seccomp/madvise.cc index 738da7f..92344df 100644 --- a/sandbox/linux/seccomp/madvise.cc +++ b/sandbox/linux/seccomp/madvise.cc @@ -26,7 +26,7 @@ int Sandbox::sandbox_madvise(void* start, size_t length, int advice) { return static_cast<int>(rc); } -bool Sandbox::process_madvise(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_madvise(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request MAdvise madvise_req; diff --git a/sandbox/linux/seccomp/maps.cc b/sandbox/linux/seccomp/maps.cc index 0bf9c8a..2c64b7f 100644 --- a/sandbox/linux/seccomp/maps.cc +++ b/sandbox/linux/seccomp/maps.cc @@ -15,20 +15,21 @@ namespace playground { -Maps::Maps(const std::string& maps_file) : - maps_file_(maps_file), +Maps::Maps(int proc_self_maps) : + proc_self_maps_(proc_self_maps), begin_iter_(this, true, false), end_iter_(this, false, true), vsyscall_(0) { - int fd = open(maps_file.c_str(), O_RDONLY); Sandbox::SysCalls sys; - if (fd >= 0) { + if (proc_self_maps_ >= 0 && + !sys.lseek(proc_self_maps_, 0, SEEK_SET)) { char buf[256] = { 0 }; int len = 0, rc = 1; bool long_line = false; do { if (rc > 0) { - rc = Sandbox::read(sys, fd, buf + len, sizeof(buf) - len - 1); + rc = Sandbox::read(sys, proc_self_maps_, buf + len, + sizeof(buf) - len - 1); if (rc > 0) { len += rc; } @@ -95,7 +96,6 @@ Maps::Maps(const std::string& maps_file) : } } } while (len || long_line); - NOINTR_SYS(close(fd)); } } @@ -155,8 +155,7 @@ char* Maps::allocNearAddr(char* addr, size_t size, int prot) const { // we will be able to perform relative 32bit jumps from the target address. size = (size + 4095) & ~4095; Sandbox::SysCalls sys; - int fd = sys.open(maps_file_.c_str(), O_RDONLY, 0); - if (fd < 0) { + if (sys.lseek(proc_self_maps_, 0, SEEK_SET)) { return NULL; } @@ -168,7 +167,8 @@ char* Maps::allocNearAddr(char* addr, size_t size, int prot) const { do { if (rc > 0) { do { - rc = Sandbox::read(sys, fd, buf + len, sizeof(buf) - len - 1); + rc = Sandbox::read(sys, proc_self_maps_, buf + len, + sizeof(buf) - len - 1); if (rc > 0) { len += rc; } @@ -213,7 +213,6 @@ char* Maps::allocNearAddr(char* addr, size_t size, int prot) const { } while (len || long_line); new_addr = NULL; done: - sys.close(fd); return new_addr; } diff --git a/sandbox/linux/seccomp/maps.h b/sandbox/linux/seccomp/maps.h index 9ecd140..1d30506 100644 --- a/sandbox/linux/seccomp/maps.h +++ b/sandbox/linux/seccomp/maps.h @@ -19,7 +19,7 @@ class Library; class Maps { friend class Library; public: - Maps(const std::string& maps_file); + Maps(int proc_self_maps); ~Maps() { } protected: @@ -69,12 +69,12 @@ class Maps { char* vsyscall() const { return vsyscall_; } protected: - const std::string maps_file_; - const Iterator begin_iter_; - const Iterator end_iter_; + const int proc_self_maps_; + const Iterator begin_iter_; + const Iterator end_iter_; - LibraryMap libs_; - char* vsyscall_; + LibraryMap libs_; + char* vsyscall_; }; } // namespace diff --git a/sandbox/linux/seccomp/mmap.cc b/sandbox/linux/seccomp/mmap.cc index 9ffd110..cefef3a 100644 --- a/sandbox/linux/seccomp/mmap.cc +++ b/sandbox/linux/seccomp/mmap.cc @@ -30,7 +30,7 @@ void* Sandbox::sandbox_mmap(void *start, size_t length, int prot, int flags, return rc; } -bool Sandbox::process_mmap(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_mmap(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request SysCalls sys; diff --git a/sandbox/linux/seccomp/mprotect.cc b/sandbox/linux/seccomp/mprotect.cc index 1852b7d..11295c7 100644 --- a/sandbox/linux/seccomp/mprotect.cc +++ b/sandbox/linux/seccomp/mprotect.cc @@ -26,8 +26,9 @@ int Sandbox::sandbox_mprotect(const void *addr, size_t len, int prot) { return static_cast<int>(rc); } -bool Sandbox::process_mprotect(int parentProc, int sandboxFd, int threadFdPub, - int threadFd, SecureMem::Args* mem) { +bool Sandbox::process_mprotect(int parentMapsFd, int sandboxFd, + int threadFdPub, int threadFd, + SecureMem::Args* mem) { // Read request SysCalls sys; MProtect mprotect_req; diff --git a/sandbox/linux/seccomp/munmap.cc b/sandbox/linux/seccomp/munmap.cc index ddab897..d9d74ad 100644 --- a/sandbox/linux/seccomp/munmap.cc +++ b/sandbox/linux/seccomp/munmap.cc @@ -25,7 +25,7 @@ int Sandbox::sandbox_munmap(void* start, size_t length) { return static_cast<int>(rc); } -bool Sandbox::process_munmap(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_munmap(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request SysCalls sys; diff --git a/sandbox/linux/seccomp/open.cc b/sandbox/linux/seccomp/open.cc index 9b4786b..982d768 100644 --- a/sandbox/linux/seccomp/open.cc +++ b/sandbox/linux/seccomp/open.cc @@ -30,7 +30,7 @@ int Sandbox::sandbox_open(const char *pathname, int flags, mode_t mode) { return static_cast<int>(rc); } -bool Sandbox::process_open(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_open(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request SysCalls sys; @@ -70,7 +70,7 @@ bool Sandbox::process_open(int parentProc, int sandboxFd, int threadFdPub, return false; } - SecureMem::lockSystemCall(parentProc, mem); + SecureMem::lockSystemCall(parentMapsFd, mem); if (read(sys, sandboxFd, mem->pathname, open_req.path_length) != (ssize_t)open_req.path_length) { goto read_parm_failed; @@ -83,7 +83,7 @@ bool Sandbox::process_open(int parentProc, int sandboxFd, int threadFdPub, "\"").c_str()); // Tell trusted thread to open the file. - SecureMem::sendSystemCall(threadFdPub, true, parentProc, mem, __NR_open, + SecureMem::sendSystemCall(threadFdPub, true, parentMapsFd, mem, __NR_open, mem->pathname - (char*)mem + (char*)mem->self, open_req.flags, open_req.mode); return true; diff --git a/sandbox/linux/seccomp/sandbox.cc b/sandbox/linux/seccomp/sandbox.cc index 9d80f63..416502b 100644 --- a/sandbox/linux/seccomp/sandbox.cc +++ b/sandbox/linux/seccomp/sandbox.cc @@ -5,6 +5,7 @@ namespace playground { // Global variables +int Sandbox::proc_self_maps_ = -1; enum Sandbox::SandboxStatus Sandbox::status_ = STATUS_UNKNOWN; int Sandbox::pid_; int Sandbox::processFdPub_; @@ -340,21 +341,20 @@ void (*Sandbox::segv())(int signo) { return fnc; } -void Sandbox::snapshotMemoryMappings(int processFd) { +void Sandbox::snapshotMemoryMappings(int processFd, int proc_self_maps) { SysCalls sys; - int mapsFd = sys.open("/proc/self/maps", O_RDONLY, 0); - if (mapsFd < 0 || !sendFd(processFd, mapsFd, -1, NULL, 0)) { + if (sys.lseek(proc_self_maps, 0, SEEK_SET) || + !sendFd(processFd, proc_self_maps, -1, NULL, 0)) { failure: die("Cannot access /proc/self/maps"); } - NOINTR_SYS(sys.close(mapsFd)); int dummy; if (read(sys, processFd, &dummy, sizeof(dummy)) != sizeof(dummy)) { goto failure; } } -int Sandbox::supportsSeccompSandbox() { +int Sandbox::supportsSeccompSandbox(int proc_fd) { if (status_ != STATUS_UNKNOWN) { return status_ != STATUS_UNSUPPORTED; } @@ -376,10 +376,23 @@ int Sandbox::supportsSeccompSandbox() { dup2(devnull, 1); dup2(devnull, 2); } + if (proc_fd >= 0) { + setProcSelfMaps(sys.openat(proc_fd, "self/maps", O_RDONLY, 0)); + } startSandbox(); write(sys, fds[1], "", 1); - _exit(0); - sys.exit_group(0); + + // Try to tell the trusted thread to shut down the entire process in an + // orderly fashion + defaultSystemCallHandler(__NR_exit_group, 0, 0, 0, 0, 0, 0); + + // If that did not work (e.g. because the kernel does not know about the + // exit_group() system call), make a direct _exit() system call instead. + // This system call is unrestricted in seccomp mode, so it will always + // succeed. Normally, we don't like it, because unlike exit_group() it + // does not terminate any other thread. But since we know that + // exit_group() exists in all kernels which support kernel-level threads, + // this is OK we only get here for old kernels where _exit() is OK. sys._exit(0); } default: @@ -397,6 +410,10 @@ int Sandbox::supportsSeccompSandbox() { } } +void Sandbox::setProcSelfMaps(int proc_self_maps) { + proc_self_maps_ = proc_self_maps; +} + void Sandbox::startSandbox() { if (status_ == STATUS_UNSUPPORTED) { die("The seccomp sandbox is not supported on this computer"); @@ -405,6 +422,12 @@ void Sandbox::startSandbox() { } SysCalls sys; + if (proc_self_maps_ < 0) { + proc_self_maps_ = sys.open("/proc/self/maps", O_RDONLY, 0); + if (proc_self_maps_ < 0) { + die("Cannot access \"/proc/self/maps\""); + } + } // The pid is unchanged for the entire program, so we can retrieve it once // and store it in a global variable. @@ -430,7 +453,7 @@ void Sandbox::startSandbox() { // view, if this code fails to identify system calls, we are still behaving // correctly. { - Maps maps("/proc/self/maps"); + Maps maps(proc_self_maps_); const char *libs[] = { "ld", "libc", "librt", "libpthread", NULL }; // Intercept system calls in the VDSO segment (if any). This has to happen @@ -470,7 +493,9 @@ void Sandbox::startSandbox() { // Take a snapshot of the current memory mappings. These mappings will be // off-limits to all future mmap(), munmap(), mremap(), and mprotect() calls. - snapshotMemoryMappings(processFdPub_); + snapshotMemoryMappings(processFdPub_, proc_self_maps_); + NOINTR_SYS(sys.close(proc_self_maps_)); + proc_self_maps_ = -1; // Creating the trusted thread enables sandboxing createTrustedThread(processFdPub_, cloneFdPub_, secureMem); diff --git a/sandbox/linux/seccomp/sandbox.h b/sandbox/linux/seccomp/sandbox.h index 4c5d10a..9873e9d 100644 --- a/sandbox/linux/seccomp/sandbox.h +++ b/sandbox/linux/seccomp/sandbox.h @@ -1,7 +1,8 @@ #ifndef SANDBOX_H__ #define SANDBOX_H__ -extern "C" int SupportsSeccompSandbox(); +extern "C" int SupportsSeccompSandbox(int proc_fd); +extern "C" void SeccompSandboxSetProcSelfMaps(int proc_self_maps); extern "C" void StartSeccompSandbox(); #endif // SANDBOX_H__ diff --git a/sandbox/linux/seccomp/sandbox_impl.h b/sandbox/linux/seccomp/sandbox_impl.h index d1cc3ef..2a7366f 100644 --- a/sandbox/linux/seccomp/sandbox_impl.h +++ b/sandbox/linux/seccomp/sandbox_impl.h @@ -49,12 +49,23 @@ class Sandbox { // This could be because the kernel does not support Seccomp mode, or it // could be because we fail to successfully rewrite all system call entry // points. - static int supportsSeccompSandbox() asm("SupportsSeccompSandbox"); + // "proc_fd" should be a file descriptor for "/proc", or -1 if not provided + // by the caller. + static int supportsSeccompSandbox(int proc_fd) + asm("SupportsSeccompSandbox"); + + // The sandbox needs to be able to access "/proc/self/maps". If this file + // is not accessible when "startSandbox()" gets called, the caller can + // provide an already opened file descriptor by calling "setProcSelfMaps()". + // The sandbox becomes the newer owner of this file descriptor and will + // eventually close it when "startSandbox()" executes. + static void setProcSelfMaps(int proc_self_maps) + asm("SeccompSandboxSetProcSelfMaps"); // This is the main public entry point. It finds all system calls that // need rewriting, sets up the resources needed by the sandbox, and // enters Seccomp mode. - static void startSandbox() asm("StartSeccompSandbox"); + static void startSandbox() asm("StartSeccompSandbox"); private: // syscall_table.c has to be implemented in C, as C++ does not support @@ -589,15 +600,16 @@ class Sandbox { // memory mappings that existed when the sandbox was first enabled. Going // forward, all these mappings are off-limits for operations such as // mmap(), munmap(), and mprotect(). - static void initializeProtectedMap(int fd); + static int initializeProtectedMap(int fd); // Helper functions that allows the trusted process to get access to // "/proc/self/maps" in the sandbox. - static void snapshotMemoryMappings(int processFd); + static void snapshotMemoryMappings(int processFd, int proc_self_maps); // Main loop for the trusted process. - static void trustedProcess(int parentProc, int processFdPub, int sandboxFd, - int cloneFd, SecureMem::Args* secureArena) + static void trustedProcess(int parentMapsFd, int processFdPub, + int sandboxFd, int cloneFd, + SecureMem::Args* secureArena) __attribute__((noreturn)); // Fork()s of the trusted process. @@ -609,6 +621,7 @@ class Sandbox { static void createTrustedThread(int processFdPub, int cloneFdPub, SecureMem::Args* secureMem); + static int proc_self_maps_; static enum SandboxStatus { STATUS_UNKNOWN, STATUS_UNSUPPORTED, STATUS_AVAILABLE, STATUS_ENABLED } status_; diff --git a/sandbox/linux/seccomp/securemem.cc b/sandbox/linux/seccomp/securemem.cc index c8e59f9..2cf6903 100644 --- a/sandbox/linux/seccomp/securemem.cc +++ b/sandbox/linux/seccomp/securemem.cc @@ -16,23 +16,27 @@ void SecureMem::abandonSystemCall(int fd, int err) { } } -void SecureMem::dieIfParentDied(int parentProc) { +void SecureMem::dieIfParentDied(int parentMapsFd) { // The syscall_mutex_ should not be contended. If it is, we are either // experiencing a very unusual load of system calls that the sandbox is not // optimized for; or, more likely, the sandboxed process terminated while the // trusted process was in the middle of waiting for the mutex. We detect // this situation and terminate the trusted process. - char proc[80]; - sprintf(proc, "/proc/self/fd/%d/status", parentProc); - struct stat sb; - if (stat(proc, &sb)) { - Sandbox::die(); + int alive = !lseek(parentMapsFd, 0, SEEK_SET); + if (alive) { + char buf; + do { + alive = read(parentMapsFd, &buf, 1); + } while (alive < 0 && errno == EINTR); + } + if (!alive) { + Sandbox::die(); } } -void SecureMem::lockSystemCall(int parentProc, Args* mem) { +void SecureMem::lockSystemCall(int parentMapsFd, Args* mem) { while (!Mutex::lockMutex(&Sandbox::syscall_mutex_, 500)) { - dieIfParentDied(parentProc); + dieIfParentDied(parentMapsFd); } asm volatile( #if defined(__x86_64__) @@ -47,7 +51,7 @@ void SecureMem::lockSystemCall(int parentProc, Args* mem) { : "memory"); } -void SecureMem::sendSystemCallInternal(int fd, bool locked, int parentProc, +void SecureMem::sendSystemCallInternal(int fd, bool locked, int parentMapsFd, Args* mem, int syscallNum, void* arg1, void* arg2, void* arg3, void* arg4, void* arg5, void* arg6) { @@ -87,9 +91,9 @@ void SecureMem::sendSystemCallInternal(int fd, bool locked, int parentProc, if (Sandbox::write(sys, fd, &data, sizeof(data)) != sizeof(data)) { Sandbox::die("Failed to send system call"); } - if (parentProc >= 0) { + if (parentMapsFd >= 0) { while (!Mutex::waitForUnlock(&Sandbox::syscall_mutex_, 500)) { - dieIfParentDied(parentProc); + dieIfParentDied(parentMapsFd); } } } diff --git a/sandbox/linux/seccomp/socketcall.cc b/sandbox/linux/seccomp/socketcall.cc index d51431d..fe88fa5 100644 --- a/sandbox/linux/seccomp/socketcall.cc +++ b/sandbox/linux/seccomp/socketcall.cc @@ -204,8 +204,9 @@ int Sandbox::sandbox_getsockopt(int sockfd, int level, int optname, return static_cast<int>(rc); } -bool Sandbox::process_recvfrom(int parentProc, int sandboxFd, int threadFdPub, - int threadFd, SecureMem::Args* mem) { +bool Sandbox::process_recvfrom(int parentMapsFd, int sandboxFd, + int threadFdPub, int threadFd, + SecureMem::Args* mem) { // Read request RecvFrom recvfrom_req; SysCalls sys; @@ -231,7 +232,7 @@ bool Sandbox::process_recvfrom(int parentProc, int sandboxFd, int threadFdPub, return true; } -bool Sandbox::process_recvmsg(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_recvmsg(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request RecvMsg recvmsg_req; @@ -255,7 +256,7 @@ bool Sandbox::process_recvmsg(int parentProc, int sandboxFd, int threadFdPub, return true; } -bool Sandbox::process_sendmsg(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_sendmsg(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request struct { @@ -307,7 +308,7 @@ bool Sandbox::process_sendmsg(int parentProc, int sandboxFd, int threadFdPub, // This must be a locked system call, because we have to ensure that the // untrusted code does not tamper with the msghdr after we have examined it. - SecureMem::lockSystemCall(parentProc, mem); + SecureMem::lockSystemCall(parentMapsFd, mem); if (sizeof(extra) > 0) { if (data.msg.msg_namelen > 0) { data.msg.msg_name = mem->pathname + sizeof(struct msghdr); @@ -319,14 +320,14 @@ bool Sandbox::process_sendmsg(int parentProc, int sandboxFd, int threadFdPub, memcpy(mem->pathname + sizeof(struct msghdr), extra, sizeof(extra)); } memcpy(mem->pathname, &data.msg, sizeof(struct msghdr)); - SecureMem::sendSystemCall(threadFdPub, true, parentProc, mem, + SecureMem::sendSystemCall(threadFdPub, true, parentMapsFd, mem, __NR_sendmsg, data.sendmsg_req.sockfd, mem->pathname - (char*)mem + (char*)mem->self, data.sendmsg_req.flags); return true; } -bool Sandbox::process_sendto(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_sendto(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request SendTo sendto_req; @@ -359,7 +360,7 @@ bool Sandbox::process_sendto(int parentProc, int sandboxFd, int threadFdPub, return true; } -bool Sandbox::process_setsockopt(int parentProc, int sandboxFd, +bool Sandbox::process_setsockopt(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request @@ -423,7 +424,7 @@ bool Sandbox::process_setsockopt(int parentProc, int sandboxFd, return false; } -bool Sandbox::process_getsockopt(int parentProc, int sandboxFd, +bool Sandbox::process_getsockopt(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request @@ -706,7 +707,7 @@ int Sandbox::sandbox_socketcall(int call, void* args) { return static_cast<int>(rc); } -bool Sandbox::process_socketcall(int parentProc, int sandboxFd, +bool Sandbox::process_socketcall(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request @@ -824,9 +825,9 @@ bool Sandbox::process_socketcall(int parentProc, int sandboxFd, // that should not be tampered with after it has been inspected. Copy it // into the write-protected securely shared memory before telling the // trusted thread to execute the socket call. - SecureMem::lockSystemCall(parentProc, mem); + SecureMem::lockSystemCall(parentMapsFd, mem); memcpy(mem->pathname, &socketcall_req.args, sizeof(socketcall_req.args)); - SecureMem::sendSystemCall(threadFdPub, true, parentProc, mem, + SecureMem::sendSystemCall(threadFdPub, true, parentMapsFd, mem, __NR_socketcall, socketcall_req.call, mem->pathname - (char*)mem + (char*)mem->self); return true; @@ -970,7 +971,7 @@ bool Sandbox::process_socketcall(int parentProc, int sandboxFd, // This must be a locked system call, because we have to ensure that // the untrusted code does not tamper with the msghdr after we have // examined it. - SecureMem::lockSystemCall(parentProc, mem); + SecureMem::lockSystemCall(parentMapsFd, mem); socketcall_req.args.sendmsg.msg = reinterpret_cast<struct msghdr*>(mem->pathname + sizeof(socketcall_req.args) - @@ -989,7 +990,7 @@ bool Sandbox::process_socketcall(int parentProc, int sandboxFd, sendmsgExtra, numSendmsgExtra); } memcpy(mem->pathname + sizeof(socketcall_req.args), msg, sizeof(*msg)); - SecureMem::sendSystemCall(threadFdPub, true, parentProc, mem, + SecureMem::sendSystemCall(threadFdPub, true, parentMapsFd, mem, __NR_socketcall, socketcall_req.call, mem->pathname - (char*)mem + (char*)mem->self); return true; diff --git a/sandbox/linux/seccomp/stat.cc b/sandbox/linux/seccomp/stat.cc index 8634fdf..7f958c6 100644 --- a/sandbox/linux/seccomp/stat.cc +++ b/sandbox/linux/seccomp/stat.cc @@ -59,7 +59,7 @@ int Sandbox::sandbox_stat64(const char *path, void *buf) { } #endif -bool Sandbox::process_stat(int parentProc, int sandboxFd, int threadFdPub, +bool Sandbox::process_stat(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMem::Args* mem) { // Read request SysCalls sys; @@ -85,7 +85,7 @@ bool Sandbox::process_stat(int parentProc, int sandboxFd, int threadFdPub, } return false; } - SecureMem::lockSystemCall(parentProc, mem); + SecureMem::lockSystemCall(parentMapsFd, mem); if (read(sys, sandboxFd, mem->pathname, stat_req.path_length) != (ssize_t)stat_req.path_length) { goto read_parm_failed; @@ -97,7 +97,7 @@ bool Sandbox::process_stat(int parentProc, int sandboxFd, int threadFdPub, "\"").c_str()); // Tell trusted thread to stat the file. - SecureMem::sendSystemCall(threadFdPub, true, parentProc, mem, + SecureMem::sendSystemCall(threadFdPub, true, parentMapsFd, mem, #if defined(__i386__) stat_req.sysnum == __NR_stat64 ? __NR_stat64 : #endif diff --git a/sandbox/linux/seccomp/syscall_table.h b/sandbox/linux/seccomp/syscall_table.h index 49c2880..fffcdb7 100644 --- a/sandbox/linux/seccomp/syscall_table.h +++ b/sandbox/linux/seccomp/syscall_table.h @@ -16,7 +16,7 @@ namespace playground { struct SyscallTable { void *handler; - bool (*trustedProcess)(int parentProc, int sandboxFd, int threadFdPub, + bool (*trustedProcess)(int parentMapsFd, int sandboxFd, int threadFdPub, int threadFd, SecureMemArgs* mem); }; extern const struct SyscallTable syscallTable[] diff --git a/sandbox/linux/seccomp/trusted_process.cc b/sandbox/linux/seccomp/trusted_process.cc index b4bee94..3686277 100644 --- a/sandbox/linux/seccomp/trusted_process.cc +++ b/sandbox/linux/seccomp/trusted_process.cc @@ -21,7 +21,7 @@ SecureMem::Args* Sandbox::getSecureMem() { return NULL; } -void Sandbox::trustedProcess(int parentProc, int processFdPub, int sandboxFd, +void Sandbox::trustedProcess(int parentMapsFd, int processFdPub, int sandboxFd, int cloneFd, SecureMem::Args* secureArena) { std::map<long long, struct Thread> threads; SysCalls sys; @@ -99,7 +99,7 @@ newThreadCreated: // Dispatch system call to handler function. Treat both exit() and clone() // specially. - if (syscallTable[header.sysnum].trustedProcess(parentProc, + if (syscallTable[header.sysnum].trustedProcess(parentMapsFd, sandboxFd, currentThread->fdPub, currentThread->fd, @@ -117,7 +117,7 @@ newThreadCreated: } } -void Sandbox::initializeProtectedMap(int fd) { +int Sandbox::initializeProtectedMap(int fd) { int mapsFd; if (!getFd(fd, &mapsFd, NULL, NULL, NULL)) { maps_failure: @@ -152,8 +152,6 @@ void Sandbox::initializeProtectedMap(int fd) { } truncated = strchr(line, '\n') == NULL; } - SysCalls sys; - NOINTR_SYS(sys.close(mapsFd)); // Prevent low address memory allocations. Some buggy kernels allow those if (protectedMap_[0] < (64 << 10)) { @@ -161,9 +159,12 @@ void Sandbox::initializeProtectedMap(int fd) { } // Let the sandbox know that we are done parsing the memory map. + SysCalls sys; if (write(sys, fd, &mapsFd, sizeof(mapsFd)) != sizeof(mapsFd)) { goto maps_failure; } + + return mapsFd; } SecureMem::Args* Sandbox::createTrustedProcess(int processFdPub, int sandboxFd, @@ -189,13 +190,6 @@ SecureMem::Args* Sandbox::createTrustedProcess(int processFdPub, int sandboxFd, syscall_mutex_ = 0x80000000; - // Hold on to a file handle in the parent's process directory. We can use - // this later to reliably tell if the parent died. - int parentProc = open("/proc/self/", O_RDONLY|O_DIRECTORY); - if (parentProc < 0) { - die("Failed to access /proc/self"); - } - // Create a trusted process that can evaluate system call parameters and // decide whether a system call should execute. This process runs outside of // the seccomp sandbox. It communicates with the sandbox'd process through @@ -211,7 +205,7 @@ SecureMem::Args* Sandbox::createTrustedProcess(int processFdPub, int sandboxFd, // If we don't know the list of our open file handles, just try closing // all valid ones. for (int fd = sysconf(_SC_OPEN_MAX); --fd > 2; ) { - if (fd != parentProc && fd != sandboxFd && fd != cloneFd) { + if (fd != sandboxFd && fd != cloneFd) { close(fd); } } @@ -224,8 +218,7 @@ SecureMem::Args* Sandbox::createTrustedProcess(int processFdPub, int sandboxFd, continue; int fd = atoi(res->d_name); if (fd > 2 && - fd != parentProc && fd != sandboxFd && fd != cloneFd && - fd != dirfd(dir)) { + fd != sandboxFd && fd != cloneFd && fd != dirfd(dir)) { close(fd); } } @@ -241,15 +234,15 @@ SecureMem::Args* Sandbox::createTrustedProcess(int processFdPub, int sandboxFd, #endif } - initializeProtectedMap(sandboxFd); - trustedProcess(parentProc, processFdPub, sandboxFd, cloneFd, secureArena); + int parentMapsFd = initializeProtectedMap(sandboxFd); + trustedProcess(parentMapsFd, processFdPub, sandboxFd, + cloneFd, secureArena); die(); } // We are still in the untrusted code. Deny access to restricted resources. mprotect(secureArena, 8192*kMaxThreads, PROT_NONE); mprotect(&syscall_mutex_, 4096, PROT_NONE); - close(parentProc); close(sandboxFd); return secureArena; |