Index: sandbox/linux/seccomp/sandbox.cc |
=================================================================== |
--- sandbox/linux/seccomp/sandbox.cc (revision 45661) |
+++ sandbox/linux/seccomp/sandbox.cc (working copy) |
@@ -121,7 +121,8 @@ |
// 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(); |
+ sa.sa_sigaction_ = segv(); |
+ sa.sa_flags = SA_SIGINFO; |
sys.sigaction(SIGSEGV, &sa, NULL); |
// Unblock SIGSEGV and SIGCHLD |
@@ -131,8 +132,8 @@ |
sys.sigprocmask(SIG_UNBLOCK, &mask, 0); |
} |
-void (*Sandbox::segv())(int signo) { |
- void (*fnc)(int signo); |
+void (*Sandbox::segv())(int signo, SysCalls::siginfo *context, void *unused) { |
+ void (*fnc)(int signo, SysCalls::siginfo *context, void *unused); |
asm volatile( |
"call 999f\n" |
#if defined(__x86_64__) |
@@ -198,7 +199,7 @@ |
// rewrite the system call instruction. Retrieve the CPU register |
// at the time of the segmentation fault and invoke syscallWrapper(). |
"8:cmpw $0x00CD, (%%r15)\n" // INT $0x0 |
- "jnz 14f\n" |
+ "jnz 16f\n" |
#ifndef NDEBUG |
"lea 200f(%%rip), %%rdi\n" |
"call playground$debugMessage\n" |
@@ -239,10 +240,18 @@ |
"mov %%r10, 0(%%rdx)\n" // old_set |
"jmp 7b\n" |
+ // Handle rt_sigreturn() |
+ "12:cmp $15, %%rax\n" // NR_rt_sigreturn |
+ "jnz 14f\n" |
+ "mov 0xA8(%%rsp), %%rsp\n" // %rsp at time of segmentation fault |
+ "13:syscall\n" // rt_sigreturn() is unrestricted |
+ "mov $66, %%edi\n" // rt_sigreturn() should never return |
+ "mov $231, %%eax\n" // NR_exit_group |
+ "jmp 13b\n" |
// Copy signal frame onto new stack. See clone.cc for details |
- "12:cmp $56+0xF000, %%rax\n" // NR_clone + 0xF000 |
- "jnz 13f\n" |
+ "14:cmp $56+0xF000, %%rax\n" // NR_clone + 0xF000 |
+ "jnz 15f\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 |
@@ -256,7 +265,7 @@ |
"jmp 7b\n" |
// Forward system call to syscallWrapper() |
- "13:lea 7b(%%rip), %%rcx\n" |
+ "15:lea 7b(%%rip), %%rcx\n" |
"push %%rcx\n" |
"push 0xB8(%%rsp)\n" // %rip at time of segmentation fault |
"lea playground$syscallWrapper(%%rip), %%rcx\n" |
@@ -265,7 +274,7 @@ |
// 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. |
- "14:mov $2, %%edi\n" // stderr |
+ "16:mov $2, %%edi\n" // stderr |
"lea 300f(%%rip), %%rsi\n" // "Segmentation fault\n" |
"mov $301f-300f, %%edx\n" |
"mov $1, %%eax\n" // NR_write |
@@ -277,13 +286,13 @@ |
// happened. If it is RDTSC, forward the request to the trusted |
// thread. |
"mov $-3, %%ebx\n" // request for RDTSC |
- "mov 0x40(%%esp), %%ebp\n" // %eip at time of segmentation fault |
+ "mov 0xDC(%%esp), %%ebp\n" // %eip at time of segmentation fault |
"cmpw $0x310F, (%%ebp)\n" // RDTSC |
"jz 0f\n" |
- "cmpw $0x010F, (%%ebp)\n" |
- "jnz 8f\n" |
+ "cmpw $0x010F, (%%ebp)\n" // RDTSCP |
+ "jnz 9f\n" |
"cmpb $0xF9, 2(%%ebp)\n" |
- "jnz 8f\n" |
+ "jnz 9f\n" |
"mov $-4, %%ebx\n" // request for RDTSCP |
"0:" |
#ifndef NDEBUG |
@@ -292,7 +301,7 @@ |
"call playground$debugMessage\n" |
"sub $4, %%esp\n" |
#else |
- "sub $8, %%esp\n" |
+ "sub $8, %%esp\n" // allocate buffer for receiving timestamp |
#endif |
"push %%ebx\n" |
"mov %%fs:16, %%ebx\n" // fd = threadFdPub |
@@ -301,126 +310,178 @@ |
"1:mov %%edx, %%eax\n" // NR_write |
"int $0x80\n" |
"cmp %%eax, %%edx\n" |
- "jz 5f\n" |
+ "jz 7f\n" |
"cmp $-4, %%eax\n" // EINTR |
"jz 1b\n" |
- "2:add $12, %%esp\n" |
- "movl $0, 0x34(%%esp)\n" // %eax at time of segmentation fault |
- "movl $0, 0x2C(%%esp)\n" // %edx at time of segmentation fault |
+ "2:add $12, %%esp\n" // remove temporary buffer from stack |
+ "xor %%eax, %%eax\n" |
+ "movl $0, 0xC8(%%esp)\n" // %edx at time of segmentation fault |
"cmpw $0x310F, (%%ebp)\n" // RDTSC |
"jz 3f\n" |
- "movl $0, 0x30(%%esp)\n" // %ecx at time of segmentation fault |
- "3:addl $2, 0x40(%%esp)\n" // %eip at time of segmentation fault |
- "mov 0x40(%%esp), %%ebp\n" // %eip at time of segmentation fault |
- "cmpw $0x010F, (%%ebp)\n" // RDTSC |
- "jnz 4f\n" |
- "addl $1, 0x40(%%esp)\n" // %eip at time of segmentation fault |
- "4:ret\n" |
- "5:mov $12, %%edx\n" // len = 3*sizeof(int) |
- "6:mov $3, %%eax\n" // NR_read |
+ "movl $0, 0xCC(%%esp)\n" // %ecx at time of segmentation fault |
+ "3:mov %%eax, 0xD0(%%esp)\n" // %eax at time of segmentation fault |
+ "4:mov 0xDC(%%esp), %%ebp\n" // %eip at time of segmentation fault |
+ "addl $2, 0xDC(%%esp)\n" // %eip at time of segmentation fault |
+ "cmpw $0x010F, (%%ebp)\n" // RDTSCP |
+ "jnz 5f\n" |
+ "addl $1, 0xDC(%%esp)\n" // %eip at time of segmentation fault |
+ "5:sub $0x1C8, %%esp\n" // a legacy signal stack is much larger |
+ "mov 0x1CC(%%esp), %%eax\n" // push signal number |
+ "push %%eax\n" |
+ "lea 0x270(%%esp), %%esi\n" // copy siginfo register values |
+ "lea 0x4(%%esp), %%edi\n" // into new location |
+ "mov $22, %%ecx\n" |
+ "cld\n" |
+ "rep movsl\n" |
+ "mov 0x2C8(%%esp), %%ebx\n" // copy first half of signal mask |
+ "mov %%ebx, 0x54(%%esp)\n" |
+ "lea 6f, %%esi\n" // copy "magic" restorer function |
+ "push %%esi\n" // push restorer function |
+ "lea 0x2D4(%%esp), %%edi\n" // patch up retcode magic numbers |
+ "movb $2, %%cl\n" |
+ "rep movsl\n" |
+ "ret\n" // return to restorer function |
+ |
+ // The restorer function is sometimes used by gdb as a magic marker to |
+ // recognize signal stack frames. Don't change any of the next three |
+ // instructions. |
+ "6:pop %%eax\n" // remove dummy argument (signo) |
+ "mov $119, %%eax\n" // NR_sigreturn |
"int $0x80\n" |
+ "7:mov $12, %%edx\n" // len = 3*sizeof(int) |
+ "8:mov $3, %%eax\n" // NR_read |
+ "int $0x80\n" |
"cmp $-4, %%eax\n" // EINTR |
- "jz 6b\n" |
+ "jz 8b\n" |
"cmp %%eax, %%edx\n" |
"jnz 2b\n" |
"pop %%eax\n" |
"pop %%edx\n" |
"pop %%ecx\n" |
- "mov %%edx, 0x2C(%%esp)\n" // %edx at time of segmentation fault |
+ "mov %%edx, 0xC8(%%esp)\n" // %edx at time of segmentation fault |
"cmpw $0x310F, (%%ebp)\n" // RDTSC |
- "jz 7f\n" |
- "mov %%ecx, 0x30(%%esp)\n" // %ecx at time of segmentation fault |
- "7:mov %%eax, 0x34(%%esp)\n" // %eax at time of segmentation fault |
+ "jz 3b\n" |
+ "mov %%ecx, 0xCC(%%esp)\n" // %ecx at time of segmentation fault |
"jmp 3b\n" |
// If the instruction is INT 0, then this was probably the result |
// 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 $0x00CD, (%%ebp)\n" // INT $0x0 |
- "jnz 16f\n" |
+ "9:cmpw $0x00CD, (%%ebp)\n" // INT $0x0 |
+ "jnz 20f\n" |
#ifndef NDEBUG |
"lea 200f, %%eax\n" |
"push %%eax\n" |
"call playground$debugMessage\n" |
"add $0x4, %%esp\n" |
#endif |
- "mov 0x34(%%esp), %%eax\n" // %eax at time of segmentation fault |
- "mov 0x28(%%esp), %%ebx\n" // %ebx at time of segmentation fault |
- "mov 0x30(%%esp), %%ecx\n" // %ecx at time of segmentation fault |
- "mov 0x2C(%%esp), %%edx\n" // %edx at time of segmentation fault |
- "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 |
+ "mov 0xD0(%%esp), %%eax\n" // %eax at time of segmentation fault |
+ "mov 0xC4(%%esp), %%ebx\n" // %ebx at time of segmentation fault |
+ "mov 0xCC(%%esp), %%ecx\n" // %ecx at time of segmentation fault |
+ "mov 0xC8(%%esp), %%edx\n" // %edx at time of segmentation fault |
+ "mov 0xB8(%%esp), %%esi\n" // %esi at time of segmentation fault |
+ "mov 0xB4(%%esp), %%edi\n" // %edi at time of segmentation fault |
+ "mov 0xB2(%%esp), %%ebp\n" // %ebp at time of segmentation fault |
// Handle sigprocmask() and rt_sigprocmask() |
"cmp $175, %%eax\n" // NR_rt_sigprocmask |
- "jnz 9f\n" |
+ "jnz 10f\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" |
+ "jl 3b\n" |
+ "jmp 11f\n" |
+ "10:cmp $126, %%eax\n" // NR_sigprocmask |
+ "jnz 15f\n" |
"mov $-22, %%eax\n" |
- "10:mov 0x58(%%esp), %%edi\n" // signal mask at time of segmentation fault |
- "mov 0x5C(%%esp), %%ebp\n" |
+ "11:mov 0xFC(%%esp), %%edi\n" // signal mask at time of segmentation fault |
+ "mov 0x100(%%esp), %%ebp\n" |
"test %%ecx, %%ecx\n" // only set mask, if set is non-NULL |
- "jz 13f\n" |
+ "jz 14f\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" |
+ "or %%esi, 0xFC(%%esp)\n" // signal mask at time of segmentation fault |
+ "or %%ecx, 0x100(%%esp)\n" |
+ "jmp 14f\n" |
+ "12:cmp $1, %%ebx\n" // %ebx = how (SIG_UNBLOCK) |
+ "jnz 13f\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" |
+ "and %%esi, 0xFC(%%esp)\n" // signal mask at time of segmentation fault |
+ "and %%ecx, 0x100(%%esp)\n" |
+ "jmp 14f\n" |
+ "13:cmp $2, %%ebx\n" // %ebx = how (SIG_SETMASK) |
+ "jnz 3b\n" |
+ "mov %%esi, 0xFC(%%esp)\n" // signal mask at time of segmentation fault |
+ "mov %%ecx, 0x100(%%esp)\n" |
+ "14:xor %%eax, %%eax\n" |
"test %%edx, %%edx\n" // only return old mask, if set is non-NULL |
- "jz 7b\n" |
+ "jz 3b\n" |
"mov %%edi, 0(%%edx)\n" // old_set |
"mov %%ebp, 4(%%edx)\n" |
- "jmp 7b\n" |
+ "jmp 3b\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 |
+ // Handle sigreturn() and rt_sigreturn() |
+ // See syscall.cc for a discussion on how we can emulate rt_sigreturn() |
+ // by calling sigreturn() with a suitably adjusted stack. |
+ "15:cmp $119, %%eax\n" // NR_sigreturn |
+ "jnz 17f\n" |
+ "mov 0xC0(%%esp), %%esp\n" // %esp at time of segmentation fault |
+ "16:int $0x80\n" // sigreturn() is unrestricted |
+ "17:cmp $173, %%eax\n" // NR_rt_sigreturn |
+ "jnz 18f\n" |
+ "mov 0xC0(%%esp), %%esp\n" // %esp at time of segmentation fault |
+ "sub $4, %%esp\n" // add fake return address |
+ "jmp 4b\n" |
+ |
+ // Copy signal frame onto new stack. In the process, we have to convert |
+ // it from an RT signal frame to a legacy signal frame. |
+ // See clone.cc for details |
+ "18:cmp $120+0xF000, %%eax\n" // NR_clone + 0xF000 |
+ "jnz 19f\n" |
+ "mov 0xC0(%%esp), %%ecx\n" // %esp at time of segmentation fault |
+ "sub %%esp, %%ecx\n" // %ecx = size of RT stack frame |
+ "mov %%ecx, %%eax\n" |
+ "add $0x1C8, %%eax\n" // adjust for size of legacy stack frame |
+ "sub $0x100, %%ecx\n" |
"mov 0(%%edx), %%edi\n" // stack for newly clone()'d thread |
"sub %%ecx, %%edi\n" // copy onto new stack |
+ "lea 0x100(%%esp), %%esi\n" |
+ "cld\n" |
+ "rep movsb\n" // copy parts of RT stack(sigmask, FP state) |
+ "mov 0xF0(%%esp), %%ebx\n" // adjust pointer to fpstate |
+ "sub %%esi, %%ebx\n" |
+ "add %%edi, %%ebx\n" |
+ "sub %%eax, %%edi\n" |
"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" |
+ "lea 0xA4(%%esp), %%esi\n" // copy sigcontext from current stack |
+ "mov $0x16, %%ecx\n" |
+ "rep movsl\n" |
+ "mov %%ebx, -0xC(%%edi)\n" // set pointer to fpstate |
+ "mov 0xFC(%%esp), %%ebx\n" // copy first half of signal mask |
+ "mov %%ebx, -0x8(%%edi)\n" |
+ "mov %%eax, -0x2C(%%edi)\n" // return size of stack frame in %%eax |
+ "addl $2, -0x20(%%edi)\n" // adjust %eip |
+ "mov 0(%%edx), %%esp\n" |
+ "mov $119, %%eax\n" // NR_sigreturn |
+ "int $0x80\n" |
// Forward system call to syscallWrapper() |
- "15:call playground$syscallWrapper\n" |
- "jmp 7b\n" |
+ "19:call playground$syscallWrapper\n" |
+ "jmp 3b\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. |
- "16:mov $2, %%ebx\n" // stderr |
+ "20:mov $2, %%ebx\n" // stderr |
"lea 300f, %%ecx\n" // "Segmentation fault\n" |
"mov $301f-300f, %%edx\n" |
"mov $4, %%eax\n" // NR_write |
"int $0x80\n" |
- "orb $4, 0x59(%%esp)\n" // signal mask at time of segmentation fault |
- "ret\n" |
+ "orb $4, 0xFD(%%esp)\n" // signal mask at time of segmentation fault |
+ "jmp 4b\n" |
#else |
#error Unsupported target platform |
#endif |