m32r: hole in shifting pc back
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>
This commit is contained in:
@@ -251,6 +251,19 @@ give_sigsegv:
|
|||||||
return -EFAULT;
|
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
|
* OK, we're invoking a handler
|
||||||
*/
|
*/
|
||||||
@@ -259,8 +272,6 @@ static int
|
|||||||
handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
|
handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
|
||||||
sigset_t *oldset, struct pt_regs *regs)
|
sigset_t *oldset, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
unsigned short inst;
|
|
||||||
|
|
||||||
/* Are we from a system call? */
|
/* Are we from a system call? */
|
||||||
if (regs->syscall_nr >= 0) {
|
if (regs->syscall_nr >= 0) {
|
||||||
/* If so, check system call restarting.. */
|
/* If so, check system call restarting.. */
|
||||||
@@ -278,12 +289,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
|
|||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case -ERESTARTNOINTR:
|
case -ERESTARTNOINTR:
|
||||||
regs->r0 = regs->orig_r0;
|
regs->r0 = regs->orig_r0;
|
||||||
inst = *(unsigned short *)(regs->bpc - 2);
|
if (prev_insn(regs) < 0)
|
||||||
if ((inst & 0xfff0) == 0x10f0) /* trap ? */
|
return -EFAULT;
|
||||||
regs->bpc -= 2;
|
|
||||||
else
|
|
||||||
regs->bpc -= 4;
|
|
||||||
regs->syscall_nr = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +317,6 @@ static void do_signal(struct pt_regs *regs)
|
|||||||
siginfo_t info;
|
siginfo_t info;
|
||||||
int signr;
|
int signr;
|
||||||
struct k_sigaction ka;
|
struct k_sigaction ka;
|
||||||
unsigned short inst;
|
|
||||||
sigset_t *oldset;
|
sigset_t *oldset;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -353,21 +359,11 @@ static void do_signal(struct pt_regs *regs)
|
|||||||
regs->r0 == -ERESTARTSYS ||
|
regs->r0 == -ERESTARTSYS ||
|
||||||
regs->r0 == -ERESTARTNOINTR) {
|
regs->r0 == -ERESTARTNOINTR) {
|
||||||
regs->r0 = regs->orig_r0;
|
regs->r0 = regs->orig_r0;
|
||||||
inst = *(unsigned short *)(regs->bpc - 2);
|
prev_insn(regs);
|
||||||
if ((inst & 0xfff0) == 0x10f0) /* trap ? */
|
|
||||||
regs->bpc -= 2;
|
|
||||||
else
|
|
||||||
regs->bpc -= 4;
|
|
||||||
regs->syscall_nr = -1;
|
|
||||||
} else if (regs->r0 == -ERESTART_RESTARTBLOCK){
|
} else if (regs->r0 == -ERESTART_RESTARTBLOCK){
|
||||||
regs->r0 = regs->orig_r0;
|
regs->r0 = regs->orig_r0;
|
||||||
regs->r7 = __NR_restart_syscall;
|
regs->r7 = __NR_restart_syscall;
|
||||||
inst = *(unsigned short *)(regs->bpc - 2);
|
prev_insn(regs);
|
||||||
if ((inst & 0xfff0) == 0x10f0) /* trap ? */
|
|
||||||
regs->bpc -= 2;
|
|
||||||
else
|
|
||||||
regs->bpc -= 4;
|
|
||||||
regs->syscall_nr = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
|
if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
|
||||||
|
Reference in New Issue
Block a user