m32r: hole in shifting pc back
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 24 Sep 2010 05:24:53 +0000 (06:24 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 24 Sep 2010 20:54:19 +0000 (13:54 -0700)
It's a userland pointer; worse, an untrustable one since ptrace
has just provided a chance to modify it.

X-Roothole-Covering-Cabal: TINRCC
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/m32r/kernel/signal.c

index a56fcbd8abe6d4951f07faeaabc4fc506a27be43..7bbe38645ed5559395f85c5b5fce93eb3f4992e3 100644 (file)
@@ -251,6 +251,19 @@ give_sigsegv:
        return -EFAULT;
 }
 
+static int prev_insn(struct pt_regs *regs)
+{
+       u16 inst;
+       if (get_user(&inst, (u16 __user *)(regs->bpc - 2)))
+               return -EFAULT;
+       if ((inst & 0xfff0) == 0x10f0)  /* trap ? */
+               regs->bpc -= 2;
+       else
+               regs->bpc -= 4;
+       regs->syscall_nr = -1;
+       return 0;
+}
+
 /*
  * OK, we're invoking a handler
  */
@@ -259,8 +272,6 @@ static int
 handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
              sigset_t *oldset, struct pt_regs *regs)
 {
-       unsigned short inst;
-
        /* Are we from a system call? */
        if (regs->syscall_nr >= 0) {
                /* If so, check system call restarting.. */
@@ -278,12 +289,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
                        /* fallthrough */
                        case -ERESTARTNOINTR:
                                regs->r0 = regs->orig_r0;
-                               inst = *(unsigned short *)(regs->bpc - 2);
-                               if ((inst & 0xfff0) == 0x10f0)  /* trap ? */
-                                       regs->bpc -= 2;
-                               else
-                                       regs->bpc -= 4;
-                               regs->syscall_nr = -1;
+                               if (prev_insn(regs) < 0)
+                                       return -EFAULT;
                }
        }
 
@@ -310,7 +317,6 @@ static void do_signal(struct pt_regs *regs)
        siginfo_t info;
        int signr;
        struct k_sigaction ka;
-       unsigned short inst;
        sigset_t *oldset;
 
        /*
@@ -353,21 +359,11 @@ static void do_signal(struct pt_regs *regs)
                    regs->r0 == -ERESTARTSYS ||
                    regs->r0 == -ERESTARTNOINTR) {
                        regs->r0 = regs->orig_r0;
-                       inst = *(unsigned short *)(regs->bpc - 2);
-                       if ((inst & 0xfff0) == 0x10f0)  /* trap ? */
-                               regs->bpc -= 2;
-                       else
-                               regs->bpc -= 4;
-                       regs->syscall_nr = -1;
+                       prev_insn(regs);
                } else if (regs->r0 == -ERESTART_RESTARTBLOCK){
                        regs->r0 = regs->orig_r0;
                        regs->r7 = __NR_restart_syscall;
-                       inst = *(unsigned short *)(regs->bpc - 2);
-                       if ((inst & 0xfff0) == 0x10f0)  /* trap ? */
-                               regs->bpc -= 2;
-                       else
-                               regs->bpc -= 4;
-                       regs->syscall_nr = -1;
+                       prev_insn(regs);
                }
        }
        if (test_thread_flag(TIF_RESTORE_SIGMASK)) {