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: petrides@redhat.com
Signed-off-by: Andi Kleen <ak@suse.de>
#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);
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;