aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRabin Vincent <rabin@rab.in>2015-02-08 11:53:22 -0500
committerJesper Nilsson <jespern@axis.com>2015-03-25 05:51:53 -0400
commit0f72e5c0df732658d5e9e3c556c9c6928034e291 (patch)
tree01664612c9e7ba6c318196295522e187f3b41d56 /arch
parentdb4a35c651a10eddc6b48b69e1db1f46bea303fa (diff)
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 <unistd.h> #include <signal.h> #include <stdlib.h> #include <sys/time.h> #include <errno.h> 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 <viro@ZenIV.linux.org.uk> Link: http://lkml.kernel.org/r/20121208074429.GC4939@ZenIV.linux.org.uk Signed-off-by: Rabin Vincent <rabin@rab.in> Signed-off-by: Jesper Nilsson <jespern@axis.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/cris/arch-v32/kernel/entry.S5
-rw-r--r--arch/cris/arch-v32/kernel/signal.c5
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:
147 ;; Stack-frame similar to the irq heads, which is reversed in 147 ;; Stack-frame similar to the irq heads, which is reversed in
148 ;; ret_from_sys_call. 148 ;; ret_from_sys_call.
149 149
150 sub.d 92, $sp ; Skip EXS and EDA. 150 sub.d 92, $sp ; Skip EDA.
151 movem $r13, [$sp] 151 movem $r13, [$sp]
152 move.d $sp, $r8 152 move.d $sp, $r8
153 addq 14*4, $r8 153 addq 14*4, $r8
@@ -158,8 +158,9 @@ system_call:
158 move $ccs, $r4 158 move $ccs, $r4
159 move $srp, $r5 159 move $srp, $r5
160 move $erp, $r6 160 move $erp, $r6
161 move.d $r9, $r7 ; Store syscall number in EXS
161 subq 4, $sp 162 subq 4, $sp
162 movem $r6, [$r8] 163 movem $r7, [$r8]
163 ei ; Enable interrupts while processing syscalls. 164 ei ; Enable interrupts while processing syscalls.
164 move.d $r10, [$sp] 165 move.d $r10, [$sp]
165 166
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)
72 /* Make that the user-mode flag is set. */ 72 /* Make that the user-mode flag is set. */
73 regs->ccs |= (1 << (U_CCS_BITNR + CCS_SHIFT)); 73 regs->ccs |= (1 << (U_CCS_BITNR + CCS_SHIFT));
74 74
75 /* Don't perform syscall restarting */
76 regs->exs = -1;
77
75 /* Restore the old USP. */ 78 /* Restore the old USP. */
76 err |= __get_user(old_usp, &sc->usp); 79 err |= __get_user(old_usp, &sc->usp);
77 wrusp(old_usp); 80 wrusp(old_usp);
@@ -427,6 +430,8 @@ do_signal(int canrestart, struct pt_regs *regs)
427{ 430{
428 struct ksignal ksig; 431 struct ksignal ksig;
429 432
433 canrestart = canrestart && ((int)regs->exs >= 0);
434
430 /* 435 /*
431 * The common case should go fast, which is why this point is 436 * The common case should go fast, which is why this point is
432 * reached from kernel-mode. If that's the case, just return 437 * reached from kernel-mode. If that's the case, just return