Chromium Code Reviews| Index: sandbox.cc |
| =================================================================== |
| --- sandbox.cc (revision 145) |
| +++ sandbox.cc (working copy) |
| @@ -355,9 +355,9 @@ |
| "cmpw $0x310F, (%%ebp)\n" // RDTSC |
| "jz 0f\n" |
| "cmpw $0x010F, (%%ebp)\n" // RDTSCP |
| - "jnz 9f\n" |
| + "jnz 10f\n" |
| "cmpb $0xF9, 2(%%ebp)\n" |
| - "jnz 9f\n" |
| + "jnz 10f\n" |
| "mov $-4, %%ebx\n" // request for RDTSCP |
| "0:" |
| #ifndef NDEBUG |
| @@ -375,7 +375,7 @@ |
| "1:mov %%edx, %%eax\n" // NR_write |
| "int $0x80\n" |
| "cmp %%eax, %%edx\n" |
| - "jz 7f\n" |
| + "jz 8f\n" |
| "cmp $-4, %%eax\n" // EINTR |
| "jz 1b\n" |
| "2:add $12, %%esp\n" // remove temporary buffer from stack |
| @@ -390,7 +390,8 @@ |
| "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 |
| + "5:add $0x4, %%esp\n" |
| + "6:sub $0x1CC, %%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 |
| @@ -400,24 +401,14 @@ |
| "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) |
| + "7: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 |
| + "8:mov $12, %%edx\n" // len = 3*sizeof(int) |
| + "9:mov $3, %%eax\n" // NR_read |
| "int $0x80\n" |
| "cmp $-4, %%eax\n" // EINTR |
| - "jz 8b\n" |
| + "jz 9b\n" |
| "cmp %%eax, %%edx\n" |
| "jnz 2b\n" |
| "pop %%eax\n" |
| @@ -434,7 +425,7 @@ |
| // rewrite the system call instruction. Retrieve the CPU register |
| // at the time of the segmentation fault and invoke |
| // syscallEntryPointWithFrame(). |
| - "9:cmpw $0x00CD, (%%ebp)\n" // INT $0x0 |
| + "10:cmpw $0x00CD, (%%ebp)\n" // INT $0x0 |
| "jnz 20f\n" |
| #ifndef NDEBUG |
| "lea 200f, %%eax\n" |
| @@ -452,37 +443,37 @@ |
| // Handle sigprocmask() and rt_sigprocmask() |
| "cmp $175, %%eax\n" // NR_rt_sigprocmask |
| - "jnz 10f\n" |
| + "jnz 11f\n" |
| "mov $-22, %%eax\n" // -EINVAL |
| "cmp $8, %%esi\n" // %esi = sigsetsize (8 bytes = 64 signals) |
| "jl 3b\n" |
| - "jmp 11f\n" |
| - "10:cmp $126, %%eax\n" // NR_sigprocmask |
| - "jnz 15f\n" |
| + "jmp 12f\n" |
| + "11:cmp $126, %%eax\n" // NR_sigprocmask |
| + "jnz 16f\n" |
| "mov $-22, %%eax\n" |
| - "11:mov 0xFC(%%esp), %%edi\n" // signal mask at time of segmentation fault |
| + "12: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 14f\n" |
| + "jz 15f\n" |
| "mov 0(%%ecx), %%esi\n" |
| "mov 4(%%ecx), %%ecx\n" |
| "cmp $0, %%ebx\n" // %ebx = how (SIG_BLOCK) |
| - "jnz 12f\n" |
| + "jnz 13f\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" |
| + "jmp 15f\n" |
| + "13:cmp $1, %%ebx\n" // %ebx = how (SIG_UNBLOCK) |
| + "jnz 14f\n" |
| "xor $-1, %%esi\n" |
| "xor $-1, %%ecx\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) |
| + "jmp 15f\n" |
| + "14: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" |
| + "15:xor %%eax, %%eax\n" |
| "test %%edx, %%edx\n" // only return old mask, if set is non-NULL |
| "jz 3b\n" |
| "mov %%edi, 0(%%edx)\n" // old_set |
| @@ -492,10 +483,10 @@ |
| // 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 |
| + "16: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 |
| + "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 |
| @@ -516,45 +507,29 @@ |
| "push 0xE0(%%esp)\n" // %eip at time of segmentation fault |
| "jmp playground$syscallEntryPointWithFrame\n" |
| + // This was a genuine segmentation fault. Check Sandbox::sa_segv_ for |
| + // what we are supposed to do. |
| // In order to implement SA_NODEFER, we have to keep track of recursive |
| // calls to SIGSEGV handlers. This means we have to increment a counter |
| // before calling the user's signal handler, and decrement it on |
| // leaving the user's signal handler. |
| - // Some signal handlers look at the return address of the signal |
| - // stack, and more importantly "gdb" uses the call to {,rt_}sigreturn() |
| - // as a magic signature when doing stacktraces. So, we have to use |
| - // a little more unusual code to regain control after the user's |
| - // signal handler is done. We adjust the return address to point to |
| - // non-executable memory. And when we trigger another SEGV we pop the |
| - // extraneous signal frame and then call sigreturn(). |
| // N.B. We currently do not correctly adjust the SEGV counter, if the |
| // user's signal handler exits in way other than by returning (e.g. by |
| // directly calling {,rt_}sigreturn(), or by calling siglongjmp()). |
| - "20:lea 30f, %%edi\n" // rt-style restorer function |
| - "lea 31f, %%esi\n" // legacy restorer function |
| - "cmp %%ebp, %%edi\n" // check if returning from user's handler |
| - "jnz 21f\n" |
| - "decl %%fs:0x1040-0x58\n" // decrement SEGV recursion counter |
| - "mov 0xC0(%%esp), %%esp\n" // %esp at time of segmentation fault |
| - "jmp 29f\n" |
| - "21:cmp %%ebp, %%esi\n" // check if returning from user's handler |
| - "jnz 22f\n" |
| - "decl %%fs:0x1040-0x58\n" // decrement SEGV recursion counter |
| - "mov 0xC0(%%esp), %%esp\n" // %esp at time of segmentation fault |
| - "jmp 6b\n" |
| - |
| - // This was a genuine segmentation fault. Check Sandbox::sa_segv_ for |
| - // what we are supposed to do. |
| - "22:lea playground$sa_segv, %%eax\n" |
| + // N.B. On i386, we don't have any guarantees that NX protection works. |
| + // So, we don't even attempt to fake a correct restorer function. Some |
| + // callers might be confused by this and will need fixing for running |
| + // inside of the seccomp sandbox. |
| + "20:lea playground$sa_segv, %%eax\n" |
| "cmp $0, 0(%%eax)\n" // SIG_DFL |
| - "jz 23f\n" |
| + "jz 21f\n" |
| "cmp $1, 0(%%eax)\n" // SIG_IGN |
| - "jnz 24f\n" // can't really ignore synchronous signals |
| + "jnz 22f\n" // can't really ignore synchronous signals |
| // 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. |
| - "23:orb $4, 0xFD(%%esp)\n" // signal mask at time of segmentation fault |
| + "21:orb $4, 0xFD(%%esp)\n" // signal mask at time of segmentation fault |
| "jmp 5b\n" |
| // Check sa_flags: |
| @@ -568,27 +543,27 @@ |
| // |
| // TODO(markus): If/when we add support for sigaltstack(), we have to |
| // handle SA_ONSTACK. |
| - "24:cmpl $0, %%fs:0x1040-0x58\n"// check if we failed inside of SEGV handler |
| - "jnz 23b\n" // if so, then terminate program |
| + "22:cmpl $0, %%fs:0x1040-0x58\n"// check if we failed inside of SEGV handler |
| + "jnz 21b\n" // if so, then terminate program |
| "mov 0(%%eax), %%ebx\n" // sa_segv_.sa_sigaction |
| "mov 4(%%eax), %%ecx\n" // sa_segv_.sa_flags |
| "btl $31, %%ecx\n" // SA_RESETHAND |
| - "jnc 25f\n" |
| + "jnc 23f\n" |
| "movl $0, 0(%%eax)\n" // set handler to SIG_DFL |
| - "25:btl $30, %%ecx\n" // SA_NODEFER |
| - "jc 28f\n" |
| + "23:btl $30, %%ecx\n" // SA_NODEFER |
| + "jc 26f\n" |
| "btl $2, %%ecx\n" // SA_SIGINFO |
| - "jnc 26f\n" |
| - "mov %%edi, 0(%%esp)\n" // trigger a SEGV on return |
| + "jnc 24f\n" |
| + "movl $27f, 0(%%esp)\n" // trigger a SEGV on return (if NX enabled) |
|
Mark Seaborn
2010/11/09 09:40:31
I don't understand the "(if NX enabled)" comment.
|
| "incl %%fs:0x1040-0x58\n" // increment recursion counter |
| "jmp *%%ebx\n" // call user's signal handler |
| - "26:mov %%esi, 0(%%esp)\n" |
| + "24:movl $28f, 0(%%esp)\n" |
| "incl %%fs:0x1040-0x58\n" // increment recursion counter |
| // We always register the signal handler to give us rt-style signal |
| // frames. But if the user asked for legacy signal frames, we must |
| // convert the signal frame prior to calling the user's signal handler. |
| - "27:sub $0x1C8, %%esp\n" // a legacy signal stack is much larger |
| + "25:sub $0x1C8, %%esp\n" // a legacy signal stack is much larger |
| "mov 0x1CC(%%esp), %%eax\n" // push signal number |
| "push %%eax\n" |
| "mov 0x1CC(%%esp), %%eax\n" // push restorer function |
| @@ -600,32 +575,16 @@ |
| "rep movsl\n" |
| "mov 0x2CC(%%esp), %%eax\n" // copy first half of signal mask |
| "mov %%eax, 0x58(%%esp)\n" |
| - "lea 31f, %%esi\n" |
| - "lea 0x2D4(%%esp), %%edi\n" // patch up retcode magic numbers |
| - "movb $2, %%cl\n" |
| - "rep movsl\n" |
| "jmp *%%ebx\n" // call user's signal handler |
| - "28:lea 6b, %%eax\n" // set appropriate restorer function |
| - "mov %%eax, 0(%%esp)\n" |
| + "26:movl $7b, 0(%%esp)\n" // set appropriate restorer function |
| "btl $2, %%ecx\n" // SA_SIGINFO |
| - "jnc 27b\n" |
| - "lea 29f, %%eax\n" |
| - "mov %%eax, 0(%%esp)\n" // set appropriate restorer function |
| + "jnc 25b\n" |
| + "movl $6b, 0(%%esp)\n" // set appropriate restorer function |
|
Mark Seaborn
2010/11/09 09:40:31
Indentation is 1 space off
|
| "jmp *%%ebx\n" // call user's signal handler |
| - "29:pushl $30f\n" // emulate rt_sigreturn() |
| - "jmp 5b\n" |
| - |
| - // Non-executable versions of the restorer function. We use these to |
| - // trigger a SEGV upon returning from the user's signal handler, giving |
| - // us an ability to clean up prior to returning from the SEGV handler. |
| - ".pushsection .data\n" // move code into non-executable section |
| - "30:mov $173, %%eax\n" // NR_rt_sigreturn |
| - "int $0x80\n" // gdb looks for this signature when doing |
| - ".byte 0\n" // backtraces |
| - "31:pop %%eax\n" |
| - "mov $119, %%eax\n" // NR_sigreturn |
| - "int $0x80\n" |
| - ".popsection\n" |
| + "27:decl %%fs:0x1040-0x58\n" |
| + "jmp 6b\n" |
| + "28:decl %%fs:0x1040-0x58\n" |
| + "jmp 7b\n" |
| #else |
| #error Unsupported target platform |
| #endif |