From a7f8388e2c167c73b6abb3b749157aafd08f90ee Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 24 Sep 2010 06:20:35 +0100 Subject: m32r: fix rt_sigsuspend() do_signal() should know about saved_mask for it to work... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m32r/kernel/entry.S | 3 +-- arch/m32r/kernel/signal.c | 48 ++++++++++++----------------------------------- 2 files changed, 13 insertions(+), 38 deletions(-) (limited to 'arch/m32r/kernel') diff --git a/arch/m32r/kernel/entry.S b/arch/m32r/kernel/entry.S index 403869833b98..90149daa560f 100644 --- a/arch/m32r/kernel/entry.S +++ b/arch/m32r/kernel/entry.S @@ -235,8 +235,7 @@ work_resched: work_notifysig: ; deal with pending signals and ; notify-resume requests mv r0, sp ; arg1 : struct pt_regs *regs - ldi r1, #0 ; arg2 : sigset_t *oldset - mv r2, r9 ; arg3 : __u32 thread_info_flags + ldi r1, r9 ; arg2 : __u32 thread_info_flags bl do_notify_resume bra restore_all diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index 144b0f124fc7..acd69f7f3357 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -28,37 +28,6 @@ #define DEBUG_SIG 0 -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - -int do_signal(struct pt_regs *, sigset_t *); - -asmlinkage int -sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, - unsigned long r2, unsigned long r3, unsigned long r4, - unsigned long r5, unsigned long r6, struct pt_regs *regs) -{ - sigset_t newset; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&newset, unewset, sizeof(newset))) - return -EFAULT; - sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP)); - - spin_lock_irq(¤t->sighand->siglock); - current->saved_sigmask = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; -} - asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r2, unsigned long r3, unsigned long r4, @@ -332,12 +301,13 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -int do_signal(struct pt_regs *regs, sigset_t *oldset) +static int do_signal(struct pt_regs *regs) { siginfo_t info; int signr; struct k_sigaction ka; unsigned short inst; + sigset_t *oldset; /* * We want the common case to go fast, which @@ -351,7 +321,9 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) if (try_to_freeze()) goto no_signal; - if (!oldset) + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else oldset = ¤t->blocked; signr = get_signal_to_deliver(&info, &ka, regs, NULL); @@ -364,6 +336,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) /* Whee! Actually deliver the signal. */ handle_signal(signr, &ka, &info, oldset, regs); + clear_thread_flag(TIF_RESTORE_SIGMASK); return 1; } @@ -391,6 +364,10 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) regs->bpc -= 4; } } + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } return 0; } @@ -398,8 +375,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) * notification of userspace execution resumption * - triggered by current->work.notify_resume */ -void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, - __u32 thread_info_flags) +void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags) { /* Pending single-step? */ if (thread_info_flags & _TIF_SINGLESTEP) @@ -407,7 +383,7 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, /* deal with pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING) - do_signal(regs,oldset); + do_signal(regs); if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); -- cgit v1.2.3-55-g7522 From a748102430f4dbbfca3ff81ac12db6e4f1243677 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 24 Sep 2010 06:22:30 +0100 Subject: make m32r handle multiple pending signals Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m32r/kernel/entry.S | 4 ++-- arch/m32r/kernel/signal.c | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'arch/m32r/kernel') diff --git a/arch/m32r/kernel/entry.S b/arch/m32r/kernel/entry.S index 90149daa560f..225412bc227e 100644 --- a/arch/m32r/kernel/entry.S +++ b/arch/m32r/kernel/entry.S @@ -235,9 +235,9 @@ work_resched: work_notifysig: ; deal with pending signals and ; notify-resume requests mv r0, sp ; arg1 : struct pt_regs *regs - ldi r1, r9 ; arg2 : __u32 thread_info_flags + mv r1, r9 ; arg2 : __u32 thread_info_flags bl do_notify_resume - bra restore_all + bra resume_userspace ; perform syscall exit tracing ALIGN diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index acd69f7f3357..db152263484f 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -282,6 +282,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, regs->bpc -= 2; else regs->bpc -= 4; + regs->syscall_nr = -1; } } @@ -353,8 +354,8 @@ static int do_signal(struct pt_regs *regs) regs->bpc -= 2; else regs->bpc -= 4; - } - if (regs->r0 == -ERESTART_RESTARTBLOCK){ + regs->syscall_nr = -1; + } else if (regs->r0 == -ERESTART_RESTARTBLOCK){ regs->r0 = regs->orig_r0; regs->r7 = __NR_restart_syscall; inst = *(unsigned short *)(regs->bpc - 2); @@ -362,6 +363,7 @@ static int do_signal(struct pt_regs *regs) regs->bpc -= 2; else regs->bpc -= 4; + regs->syscall_nr = -1; } } if (test_thread_flag(TIF_RESTORE_SIGMASK)) { -- cgit v1.2.3-55-g7522 From a05c4e1d669d09faa90ce7b22646ad1a4b0de3ff Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 24 Sep 2010 06:23:57 +0100 Subject: m32r: don't block signals if sigframe setup has failed Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m32r/kernel/signal.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'arch/m32r/kernel') diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index db152263484f..a56fcbd8abe6 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -187,7 +187,7 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) return (void __user *)((sp - frame_size) & -8ul); } -static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, +static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { struct rt_sigframe __user *frame; @@ -244,17 +244,18 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, current->comm, current->pid, frame, regs->pc); #endif - return; + return 0; give_sigsegv: force_sigsegv(sig, current); + return -EFAULT; } /* * OK, we're invoking a handler */ -static void +static int handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { @@ -287,7 +288,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, } /* Set up the stack frame */ - setup_rt_frame(sig, ka, info, oldset, regs); + if (setup_rt_frame(sig, ka, info, oldset, regs)) + return -EFAULT; spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); @@ -295,6 +297,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); + return 0; } /* @@ -302,7 +305,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -static int do_signal(struct pt_regs *regs) +static void do_signal(struct pt_regs *regs) { siginfo_t info; int signr; @@ -317,7 +320,7 @@ static int do_signal(struct pt_regs *regs) * if so. */ if (!user_mode(regs)) - return 1; + return; if (try_to_freeze()) goto no_signal; @@ -336,9 +339,10 @@ static int do_signal(struct pt_regs *regs) */ /* Whee! Actually deliver the signal. */ - handle_signal(signr, &ka, &info, oldset, regs); - clear_thread_flag(TIF_RESTORE_SIGMASK); - return 1; + if (handle_signal(signr, &ka, &info, oldset, regs) == 0) + clear_thread_flag(TIF_RESTORE_SIGMASK); + + return; } no_signal: @@ -370,7 +374,6 @@ static int do_signal(struct pt_regs *regs) clear_thread_flag(TIF_RESTORE_SIGMASK); sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); } - return 0; } /* -- cgit v1.2.3-55-g7522 From bb9c861ee1b94c97cd98c783a2b4c1cf53ff1712 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 24 Sep 2010 06:24:53 +0100 Subject: 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 Signed-off-by: Linus Torvalds --- arch/m32r/kernel/signal.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) (limited to 'arch/m32r/kernel') diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index a56fcbd8abe6..7bbe38645ed5 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -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)) { -- cgit v1.2.3-55-g7522 From acdc0d5ef9dd74534fe8df77a2056fa1d911abe5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 24 Sep 2010 06:25:34 +0100 Subject: m32r: fix breakage from "m32r: use generic ptrace_resume code" Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- arch/m32r/kernel/ptrace.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch/m32r/kernel') diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c index e555091eb97c..0021ade4cba8 100644 --- a/arch/m32r/kernel/ptrace.c +++ b/arch/m32r/kernel/ptrace.c @@ -592,16 +592,17 @@ void user_enable_single_step(struct task_struct *child) if (access_process_vm(child, pc&~3, &insn, sizeof(insn), 0) != sizeof(insn)) - break; + return -EIO; compute_next_pc(insn, pc, &next_pc, child); if (next_pc & 0x80000000) - break; + return -EIO; if (embed_debug_trap(child, next_pc)) - break; + return -EIO; invalidate_cache(); + return 0; } void user_disable_single_step(struct task_struct *child) -- cgit v1.2.3-55-g7522