[PATCH] Always check that RIPs are canonical during signal handling
Linux Kernel Mailing List <[email protected]> Wed, 12 Apr 2006 19:59:31 GMT
| Newsgroups | gmane.linux.kernel.commits.2-4 |
|---|---|
| Message-ID | <[email protected]> |
commit e5a190da220758a739a31189440669c37fcd9773 tree 5ce75f4f0a50a2dba708533cb2b855f20cc2894d parent 09d3b3dcfa80c9094f1748c1be064b9326c9ef2b author Andi Kleen <[email protected]> Tue, 11 Apr 2006 12:34:45 +0200 committer Marcelo Tosatti <[email protected]> Thu, 13 Apr 2006 01:16:58 -0500 [PATCH] Always check that RIPs are canonical during signal handling 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. Roughly based on a patch by Ernie Petrides, but redone by AK. This is CVE-2006-0741 Cc: [email protected] Signed-off-by: Andi Kleen <[email protected]> arch/x86_64/kernel/signal.c | 19 +++++++++++++------ 1 files changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c index 99fbbbe..f438b0d 100644 --- a/arch/x86_64/kernel/signal.c +++ b/arch/x86_64/kernel/signal.c @@ -137,15 +137,18 @@ restore_sigcontext(struct pt_regs *regs, #define COPY(x) err |= __get_user(regs->x, &sc->x) -#define COPY_CANON(x) \ - COPY(x); \ - if ((regs->x >> 48) != 0 && (regs->x >> 48) != 0xffff) \ - regs->x = 0; /* fs and gs are ignored because we cannot handle the 64bit base easily */ - COPY(rdi); COPY(rsi); COPY(rbp); COPY_CANON(rsp); COPY(rbx); - COPY(rdx); COPY(rcx); COPY_CANON(rip); + 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) { + regs->rip = 0; + regs->rsp = 0; + return -EFAULT; + } COPY(r8); COPY(r9); COPY(r10); @@ -357,6 +360,10 @@ static void setup_rt_frame(int sig, stru regs->rdx = (unsigned long)&frame->uc; regs->rsp = (unsigned long) frame; regs->rip = (unsigned long) ka->sa.sa_handler; + if (regs->rip >= TASK_SIZE) { + regs->rip = 0; + goto give_sigsegv; + } regs->cs = __USER_CS; regs->ss = __USER_DS;