From 0f72e5c0df732658d5e9e3c556c9c6928034e291 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sun, 8 Feb 2015 17:53:22 +0100 Subject: [PATCH] CRISv32: prevent bogus restarts on sigreturn Al Viro noted that CRIS is vulnerable to bogus restarts on sigreturn. The fixes CRISv32 by using regs->exs as an additional indicator to whether we should attempt to restart the syscall or not. EXS is only used in the sigtrap handling, and in that path we already have r9 (the other indicator, which indicates if we're in a syscall or not) cleared. Test case, a port of Al's ARM version from 653d48b22166db2d8 ("arm: fix really nasty sigreturn bug"): #include #include #include #include #include void f(int n) { register int r10 asm ("r10") = n; __asm__ __volatile__( "ba 1f \n" "nop \n" "break 8 \n" "1: ba . \n" "nop \n" : : "r" (r10) : "memory"); } void handler1(int sig) { } void handler2(int sig) { raise(1); } void handler3(int sig) { exit(0); } int main(int argc, char *argv[]) { struct sigaction s = {.sa_handler = handler2}; struct itimerval t1 = { .it_value = {1} }; struct itimerval t2 = { .it_value = {2} }; signal(1, handler1); sigemptyset(&s.sa_mask); sigaddset(&s.sa_mask, 1); sigaction(SIGALRM, &s, NULL); signal(SIGVTALRM, handler3); setitimer(ITIMER_REAL, &t1, NULL); setitimer(ITIMER_VIRTUAL, &t2, NULL); f(-513); /* -ERESTARTNOINTR */ return 0; } Reported-by: Al Viro Link: http://lkml.kernel.org/r/20121208074429.GC4939@ZenIV.linux.org.uk Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/kernel/entry.S | 5 +++-- arch/cris/arch-v32/kernel/signal.c | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S index d4c088b4044c..1ea29b7f263c 100644 --- a/arch/cris/arch-v32/kernel/entry.S +++ b/arch/cris/arch-v32/kernel/entry.S @@ -147,7 +147,7 @@ system_call: ;; Stack-frame similar to the irq heads, which is reversed in ;; ret_from_sys_call. - sub.d 92, $sp ; Skip EXS and EDA. + sub.d 92, $sp ; Skip EDA. movem $r13, [$sp] move.d $sp, $r8 addq 14*4, $r8 @@ -158,8 +158,9 @@ system_call: move $ccs, $r4 move $srp, $r5 move $erp, $r6 + move.d $r9, $r7 ; Store syscall number in EXS subq 4, $sp - movem $r6, [$r8] + movem $r7, [$r8] ei ; Enable interrupts while processing syscalls. move.d $r10, [$sp] diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index 870e3e069318..d8d13beafc02 100644 --- a/arch/cris/arch-v32/kernel/signal.c +++ b/arch/cris/arch-v32/kernel/signal.c @@ -72,6 +72,9 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) /* Make that the user-mode flag is set. */ regs->ccs |= (1 << (U_CCS_BITNR + CCS_SHIFT)); + /* Don't perform syscall restarting */ + regs->exs = -1; + /* Restore the old USP. */ err |= __get_user(old_usp, &sc->usp); wrusp(old_usp); @@ -427,6 +430,8 @@ do_signal(int canrestart, struct pt_regs *regs) { struct ksignal ksig; + canrestart = canrestart && ((int)regs->exs >= 0); + /* * The common case should go fast, which is why this point is * reached from kernel-mode. If that's the case, just return -- 2.34.1