diff options
Diffstat (limited to 'sandbox/linux/seccomp/sandbox.cc')
-rw-r--r-- | sandbox/linux/seccomp/sandbox.cc | 154 |
1 files changed, 136 insertions, 18 deletions
diff --git a/sandbox/linux/seccomp/sandbox.cc b/sandbox/linux/seccomp/sandbox.cc index 12f0c0f..b7a249e 100644 --- a/sandbox/linux/seccomp/sandbox.cc +++ b/sandbox/linux/seccomp/sandbox.cc @@ -112,25 +112,23 @@ bool Sandbox::getFd(int transport, int* fd0, int* fd1, void* buf, size_t*len) { } void Sandbox::setupSignalHandlers() { + // Set SIGCHLD to SIG_DFL so that waitpid() can work SysCalls sys; struct SysCalls::kernel_sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler_ = SIG_DFL; sys.sigaction(SIGCHLD, &sa, NULL); - // Set up SEGV handler for dealing with RDTSC instructions + // Set up SEGV handler for dealing with RDTSC instructions, system calls + // that have been rewritten to use INT0, and for sigpending() emulation. sa.sa_handler_ = segv(); sys.sigaction(SIGSEGV, &sa, NULL); - // Block all asynchronous signals, except for SIGCHLD which needs to be - // set to SIG_DFL for waitpid() to work. + // Unblock SIGSEGV and SIGCHLD SysCalls::kernel_sigset_t mask; - memset(&mask, 0xFF, sizeof(mask)); - mask.sig[0] &= ~((1 << (SIGSEGV - 1)) | (1 << (SIGINT - 1)) | - (1 << (SIGTERM - 1)) | (1 << (SIGQUIT - 1)) | - (1 << (SIGHUP - 1)) | (1 << (SIGABRT - 1)) | - (1 << (SIGCHLD - 1))); - sys.sigprocmask(SIG_SETMASK, &mask, 0); + memset(&mask, 0x00, sizeof(mask)); + mask.sig[0] |= (1 << (SIGSEGV - 1)) | (1 << (SIGCHLD - 1)); + sys.sigprocmask(SIG_UNBLOCK, &mask, 0); } void (*Sandbox::segv())(int signo) { @@ -158,7 +156,7 @@ void (*Sandbox::segv())(int signo) { "sub $4, %%rsp\n" "push %%r14\n" "mov %%gs:16, %%edi\n" // fd = threadFdPub - "mov %%rsp, %%rsi\n" // buf = %esp + "mov %%rsp, %%rsi\n" // buf = %rsp "mov $4, %%edx\n" // len = sizeof(int) "1:mov $1, %%eax\n" // NR_write "syscall\n" @@ -199,8 +197,8 @@ void (*Sandbox::segv())(int signo) { // of playground::Library being unable to find a way to safely // rewrite the system call instruction. Retrieve the CPU register // at the time of the segmentation fault and invoke syscallWrapper(). - "8:cmpw $0xCD, (%%r15)\n" // INT $0x0 - "jnz 9f\n" + "8:cmpw $0x00CD, (%%r15)\n" // INT $0x0 + "jnz 14f\n" #ifndef NDEBUG "lea 200f(%%rip), %%rdi\n" "call playground$debugMessage\n" @@ -212,7 +210,53 @@ void (*Sandbox::segv())(int signo) { "mov 0x40(%%rsp), %%r10\n" // %r10 at time of segmentation fault "mov 0x30(%%rsp), %%r8\n" // %r8 at time of segmentation fault "mov 0x38(%%rsp), %%r9\n" // %r9 at time of segmentation fault - "lea 7b(%%rip), %%rcx\n" + + // Handle rt_sigprocmask() + "cmp $14, %%rax\n" // NR_rt_sigprocmask + "jnz 12f\n" + "mov $-22, %%rax\n" // -EINVAL + "cmp $8, %%r10\n" // %r10 = sigsetsize (8 bytes = 64 signals) + "jl 7b\n" + "mov 0x130(%%rsp), %%r10\n" // signal mask at time of segmentation fault + "test %%rsi, %%rsi\n" // only set mask, if set is non-NULL + "jz 11f\n" + "mov 0(%%rsi), %%rsi\n" + "cmp $0, %%rdi\n" // %rdi = how (SIG_BLOCK) + "jnz 9f\n" + "or %%rsi, 0x130(%%rsp)\n" // signal mask at time of segmentation fault + "jmp 11f\n" + "9:cmp $1, %%rdi\n" // %rdi = how (SIG_UNBLOCK) + "jnz 10f\n" + "xor $-1, %%rsi\n" + "and %%rsi, 0x130(%%rsp)\n" // signal mask at time of segmentation fault + "jmp 11f\n" + "10:cmp $2, %%rdi\n" // %rdi = how (SIG_SETMASK) + "jnz 7b\n" + "mov %%rsi, 0x130(%%rsp)\n" // signal mask at time of segmentation fault + "11:xor %%rax, %%rax\n" + "test %%rdx, %%rdx\n" // only return old mask, if set is non-NULL + "jz 7b\n" + "mov %%r10, 0(%%rdx)\n" // old_set + "jmp 7b\n" + + + // Copy signal frame onto new stack. See clone.cc for details + "12:cmp $56+0xF000, %%rax\n" // NR_clone + 0xF000 + "jnz 13f\n" + "mov 0xA8(%%rsp), %%rcx\n" // %rsp at time of segmentation fault + "sub %%rsp, %%rcx\n" // %rcx = size of stack frame + "sub $8, %%rcx\n" // skip return address + "mov %%rcx, %%rax\n" // return size of signal stack frame + "mov 0(%%rdx), %%rdi\n" // stack for newly clone()'d thread + "sub %%rcx, %%rdi\n" // copy onto new stack + "mov %%rdi, 0(%%rdx)\n" // allocate space on new stack + "lea 8(%%rsp), %%rsi\n" // copy from current stack + "cld\n" + "rep movsb\n" + "jmp 7b\n" + + // Forward system call to syscallWrapper() + "13:lea 7b(%%rip), %%rcx\n" "push %%rcx\n" "push 0xB8(%%rsp)\n" // %rip at time of segmentation fault "lea playground$syscallWrapper(%%rip), %%rcx\n" @@ -221,7 +265,7 @@ void (*Sandbox::segv())(int signo) { // This was a genuine segmentation fault. Trigger the kernel's default // signal disposition. The only way we can do this from seccomp mode // is by blocking the signal and retriggering it. - "9:mov $2, %%edi\n" // stderr + "14:mov $2, %%edi\n" // stderr "lea 300f(%%rip), %%rsi\n" // "Segmentation fault\n" "mov $301f-300f, %%edx\n" "mov $1, %%eax\n" // NR_write @@ -293,8 +337,8 @@ void (*Sandbox::segv())(int signo) { // of playground::Library being unable to find a way to safely // rewrite the system call instruction. Retrieve the CPU register // at the time of the segmentation fault and invoke syscallWrapper(). - "8:cmpw $0xCD, (%%ebp)\n" // INT $0x0 - "jnz 9f\n" + "8:cmpw $0x00CD, (%%ebp)\n" // INT $0x0 + "jnz 16f\n" #ifndef NDEBUG "lea 200f, %%eax\n" "push %%eax\n" @@ -308,13 +352,69 @@ void (*Sandbox::segv())(int signo) { "mov 0x1C(%%esp), %%esi\n" // %esi at time of segmentation fault "mov 0x18(%%esp), %%edi\n" // %edi at time of segmentation fault "mov 0x20(%%esp), %%ebp\n" // %ebp at time of segmentation fault - "call playground$syscallWrapper\n" + + // Handle sigprocmask() and rt_sigprocmask() + "cmp $175, %%eax\n" // NR_rt_sigprocmask + "jnz 9f\n" + "mov $-22, %%eax\n" // -EINVAL + "cmp $8, %%esi\n" // %esi = sigsetsize (8 bytes = 64 signals) + "jl 7b\n" + "jmp 10f\n" + "9:cmp $126, %%eax\n" // NR_sigprocmask + "jnz 14f\n" + "mov $-22, %%eax\n" + "10:mov 0x58(%%esp), %%edi\n" // signal mask at time of segmentation fault + "mov 0x5C(%%esp), %%ebp\n" + "test %%ecx, %%ecx\n" // only set mask, if set is non-NULL + "jz 13f\n" + "mov 0(%%ecx), %%esi\n" + "mov 4(%%ecx), %%ecx\n" + "cmp $0, %%ebx\n" // %ebx = how (SIG_BLOCK) + "jnz 11f\n" + "or %%esi, 0x58(%%esp)\n" // signal mask at time of segmentation fault + "or %%ecx, 0x5C(%%esp)\n" + "jmp 13f\n" + "11:cmp $1, %%ebx\n" // %ebx = how (SIG_UNBLOCK) + "jnz 12f\n" + "xor $-1, %%esi\n" + "xor $-1, %%ecx\n" + "and %%esi, 0x58(%%esp)\n" // signal mask at time of segmentation fault + "and %%ecx, 0x5C(%%esp)\n" + "jmp 13f\n" + "12:cmp $2, %%ebx\n" // %ebx = how (SIG_SETMASK) + "jnz 7b\n" + "mov %%esi, 0x58(%%esp)\n" // signal mask at time of segmentation fault + "mov %%ecx, 0x5C(%%esp)\n" + "13:xor %%eax, %%eax\n" + "test %%edx, %%edx\n" // only return old mask, if set is non-NULL + "jz 7b\n" + "mov %%edi, 0(%%edx)\n" // old_set + "mov %%ebp, 4(%%edx)\n" + "jmp 7b\n" + + // Copy signal frame onto new stack. See clone.cc for details + "14:cmp $120+0xF000, %%eax\n" // NR_clone + 0xF000 + "jnz 15f\n" + "mov 0x24(%%esp), %%ecx\n" // %esp at time of segmentation fault + "sub %%esp, %%ecx\n" // %ecx = size of stack frame + "sub $8, %%ecx\n" // skip return address and dummy + "mov %%ecx, %%eax\n" // return size of signal stack frame + "mov 0(%%edx), %%edi\n" // stack for newly clone()'d thread + "sub %%ecx, %%edi\n" // copy onto new stack + "mov %%edi, 0(%%edx)\n" // allocate space on new stack + "lea 8(%%esp), %%esi\n" // copy from current stack + "cld\n" + "rep movsb\n" + "jmp 7b\n" + + // Forward system call to syscallWrapper() + "15:call playground$syscallWrapper\n" "jmp 7b\n" // This was a genuine segmentation fault. Trigger the kernel's default // signal disposition. The only way we can do this from seccomp mode // is by blocking the signal and retriggering it. - "9:mov $2, %%ebx\n" // stderr + "16:mov $2, %%ebx\n" // stderr "lea 300f, %%ecx\n" // "Segmentation fault\n" "mov $301f-300f, %%edx\n" "mov $4, %%eax\n" // NR_write @@ -345,6 +445,24 @@ void (*Sandbox::segv())(int signo) { return fnc; } +SecureMem::Args* Sandbox::getSecureMem() { + // Check trusted_thread.cc for the magic offset that gets us from the TLS + // to the beginning of the secure memory area. + SecureMem::Args* ret; +#if defined(__x86_64__) + asm volatile( + "movq %%gs:-0xE0, %0\n" + : "=q"(ret)); +#elif defined(__i386__) + asm volatile( + "movl %%fs:-0x58, %0\n" + : "=r"(ret)); +#else +#error Unsupported target platform +#endif + return ret; +} + void Sandbox::snapshotMemoryMappings(int processFd, int proc_self_maps) { SysCalls sys; if (sys.lseek(proc_self_maps, 0, SEEK_SET) || |