OSDN Git Service

[PATCH] x86-64: Always check that RIPs are canonical during signal handling (update)
authorAndi Kleen <ak@suse.de>
Tue, 18 Apr 2006 10:21:25 +0000 (12:21 +0200)
committerMarcelo Tosatti <marcelo@dmt.cnet>
Wed, 19 Apr 2006 22:58:31 +0000 (17:58 -0500)
Next try.

First the already existing check in COPY_CANON for sigreturn
wasn't correct. Replace it with a better check against TASK_SIZE.

Also add a check to sigaction which was missing it previously.

This works around a problem in handling non canonical RIPs on SYSRET on Intel
CPUs. They report the #GP on the SYSRET, not the next instruction
as Linux expects it. With these changes this path should never
see a non canonical user RIP.

I reset SIGSEGV to DFL to avoid an endless loop

Roughly based on a patch by Ernie Petrides, but redone by AK.

This is CVE-2006-0741

Cc: petrides@redhat.com
Signed-off-by: Andi Kleen <ak@suse.de>
arch/x86_64/kernel/signal.c

index f438b0d..8bc844f 100644 (file)
@@ -143,10 +143,8 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, unsigned long *p
        COPY(rdi); COPY(rsi); COPY(rbp); COPY(rsp); COPY(rbx);
        COPY(rdx); COPY(rcx); 
        COPY(rip);
-       /* rsp check is not strictly needed I think -AK */
-       if (regs->rip >= TASK_SIZE || regs->rsp >= TASK_SIZE) { 
+       if (regs->rip >= TASK_SIZE && regs->rip < VSYSCALL_START) { 
                regs->rip = 0;
-               regs->rsp = 0;
                return -EFAULT;
        }
        COPY(r8);
@@ -361,8 +359,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->rsp = (unsigned long) frame;
        regs->rip = (unsigned long) ka->sa.sa_handler;
        if (regs->rip >= TASK_SIZE) { 
+               if (sig == SIGSEGV)
+                       ka->sa.sa_handler = SIG_DFL;
                regs->rip = 0;
-               goto give_sigsegv;
        }
        regs->cs = __USER_CS;
        regs->ss = __USER_DS;