From 68f3f16d9ad0f1e28ab3fd0001ab5798c41f15a3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 21 May 2012 21:42:32 -0400 Subject: new helper: sigsuspend() guts of saved_sigmask-based sigsuspend/rt_sigsuspend. Takes kernel sigset_t *. Open-coded instances replaced with calling it. Signed-off-by: Al Viro diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 35f2ef4..74b05e6 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -121,17 +121,8 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act, SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask) { sigset_t blocked; - - current->saved_sigmask = current->blocked; - - mask &= _BLOCKABLE; siginitset(&blocked, mask); - set_current_blocked(&blocked); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; + return sigsuspend(&blocked); } asmlinkage int diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 73d9a42..4e5fdd9 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -67,17 +67,8 @@ const unsigned long syscall_restart_code[2] = { asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask) { sigset_t blocked; - - current->saved_sigmask = current->blocked; - - mask &= _BLOCKABLE; siginitset(&blocked, mask); - set_current_blocked(&blocked); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_restore_sigmask(); - return -ERESTARTNOHAND; + return sigsuspend(&blocked); } asmlinkage int diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c index 289c584..170f497 100644 --- a/arch/cris/arch-v10/kernel/signal.c +++ b/arch/cris/arch-v10/kernel/signal.c @@ -48,19 +48,11 @@ void do_signal(int canrestart, struct pt_regs *regs); * dummy arguments to be able to reach the regs argument. (Note that this * arrangement relies on old_sigset_t occupying one register.) */ -int sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, - long srp, struct pt_regs *regs) +int sys_sigsuspend(old_sigset_t mask) { - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - current->saved_sigmask = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; + sigset_t blocked; + siginitset(&blocked, mask); + return sigsuspend(&blocked); } int sys_sigaction(int sig, const struct old_sigaction __user *act, diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index ce4ab1a..e090832 100644 --- a/arch/cris/arch-v32/kernel/signal.c +++ b/arch/cris/arch-v32/kernel/signal.c @@ -59,19 +59,11 @@ void keep_debug_flags(unsigned long oldccs, unsigned long oldspc, * dummy arguments to be able to reach the regs argument. */ int -sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, - long srp, struct pt_regs *regs) +sys_sigsuspend(old_sigset_t mask) { - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - current->saved_sigmask = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; + sigset_t blocked; + siginitset(&blocked, mask); + return sigsuspend(&blocked); } int diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index bab0129..df957c7 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -40,17 +40,9 @@ struct fdpic_func_descriptor { */ asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) { - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - current->saved_sigmask = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; + sigset_t blocked; + siginitset(&blocked, mask); + return sigsuspend(&blocked); } asmlinkage int sys_sigaction(int sig, diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index 1747c70..8186982 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c @@ -230,18 +230,9 @@ static inline void push_cache(unsigned long vaddr) asmlinkage int sys_sigsuspend(int unused0, int unused1, old_sigset_t mask) { - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - current->saved_sigmask = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_restore_sigmask(); - - return -ERESTARTNOHAND; + sigset_t blocked; + siginitset(&blocked, mask); + return sigsuspend(&blocked); } asmlinkage int diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index d5a338a..17f6ee3 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -255,15 +255,7 @@ asmlinkage int sys_sigsuspend(nabi_no_regargs struct pt_regs regs) uset = (sigset_t __user *) regs.regs[4]; if (copy_from_user(&newset, uset, sizeof(sigset_t))) return -EFAULT; - sigdelsetmask(&newset, ~_BLOCKABLE); - - current->saved_sigmask = current->blocked; - set_current_blocked(&newset); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; + return sigsuspend(&newset); } #endif @@ -281,15 +273,7 @@ asmlinkage int sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) unewset = (sigset_t __user *) regs.regs[4]; if (copy_from_user(&newset, unewset, sizeof(newset))) return -EFAULT; - sigdelsetmask(&newset, ~_BLOCKABLE); - - current->saved_sigmask = current->blocked; - set_current_blocked(&newset); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; + return sigsuspend(&newset); } #ifdef CONFIG_TRAD_SIGNALS diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index ac3b8d8..b4fe2ea 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -288,15 +288,7 @@ asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) uset = (compat_sigset_t __user *) regs.regs[4]; if (get_sigset(&newset, uset)) return -EFAULT; - sigdelsetmask(&newset, ~_BLOCKABLE); - - current->saved_sigmask = current->blocked; - set_current_blocked(&newset); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; + return sigsuspend(&newset); } asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) @@ -313,15 +305,7 @@ asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) uset = (compat_sigset_t __user *) regs.regs[4]; if (get_sigset(&newset, uset)) return -EFAULT; - sigdelsetmask(&newset, ~_BLOCKABLE); - - current->saved_sigmask = current->blocked; - set_current_blocked(&newset); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; + return sigsuspend(&newset); } SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act, diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index 86eb4b0..63ffac9 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -91,15 +91,7 @@ asmlinkage int sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) if (copy_from_user(&uset, unewset, sizeof(uset))) return -EFAULT; sigset_from_compat(&newset, &uset); - sigdelsetmask(&newset, ~_BLOCKABLE); - - current->saved_sigmask = current->blocked; - set_current_blocked(&newset); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; + return sigsuspend(&newset); } asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c index 690f4e9..50eb94a 100644 --- a/arch/mn10300/kernel/signal.c +++ b/arch/mn10300/kernel/signal.c @@ -38,17 +38,9 @@ */ asmlinkage long sys_sigsuspend(int history0, int history1, old_sigset_t mask) { - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - current->saved_sigmask = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; + sigset_t blocked; + siginitset(&blocked, mask); + return sigsuspend(&blocked); } /* diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 45eb998..ac1f960 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -244,17 +244,8 @@ static inline int restore_general_regs(struct pt_regs *regs, long sys_sigsuspend(old_sigset_t mask) { sigset_t blocked; - - current->saved_sigmask = current->blocked; - - mask &= _BLOCKABLE; siginitset(&blocked, mask); - set_current_blocked(&blocked); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_restore_sigmask(); - return -ERESTARTNOHAND; + return sigsuspend(&blocked); } long sys_sigaction(int sig, struct old_sigaction __user *act, diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 8a4e2b7..f626232 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -59,15 +59,8 @@ typedef struct SYSCALL_DEFINE3(sigsuspend, int, history0, int, history1, old_sigset_t, mask) { sigset_t blocked; - - current->saved_sigmask = current->blocked; - mask &= _BLOCKABLE; siginitset(&blocked, mask); - set_current_blocked(&blocked); - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - set_restore_sigmask(); - return -ERESTARTNOHAND; + return sigsuspend(&blocked); } SYSCALL_DEFINE3(sigaction, int, sig, const struct old_sigaction __user *, act, diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 5901fba..46c9f9b 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c @@ -58,18 +58,8 @@ sys_sigsuspend(old_sigset_t mask, struct pt_regs __regs) { sigset_t blocked; - - current->saved_sigmask = current->blocked; - - mask &= _BLOCKABLE; siginitset(&blocked, mask); - set_current_blocked(&blocked); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_restore_sigmask(); - - return -ERESTARTNOHAND; + return sigsuspend(&blocked); } asmlinkage int diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index ac8e66b..2b7e849 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -64,18 +64,8 @@ struct rt_signal_frame { static int _sigpause_common(old_sigset_t set) { sigset_t blocked; - - current->saved_sigmask = current->blocked; - - set &= _BLOCKABLE; siginitset(&blocked, set); - set_current_blocked(&blocked); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - - return -ERESTARTNOHAND; + return sigsuspend(&blocked); } asmlinkage int sys_sigsuspend(old_sigset_t set) diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index 48b0f57..eafaab4 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -242,19 +242,8 @@ struct rt_signal_frame { static long _sigpause_common(old_sigset_t set) { sigset_t blocked; - - current->saved_sigmask = current->blocked; - - set &= _BLOCKABLE; siginitset(&blocked, set); - set_current_blocked(&blocked); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - - set_restore_sigmask(); - - return -ERESTARTNOHAND; + return sigsuspend(&blocked); } asmlinkage long sys_sigpause(unsigned int set) diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c index fb12f4c..b9b75b3 100644 --- a/arch/um/kernel/signal.c +++ b/arch/um/kernel/signal.c @@ -152,15 +152,8 @@ int do_signal(void) long sys_sigsuspend(int history0, int history1, old_sigset_t mask) { sigset_t blocked; - - mask &= _BLOCKABLE; siginitset(&blocked, mask); - set_current_blocked(&blocked); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_thread_flag(TIF_RESTORE_SIGMASK); - return -ERESTARTNOHAND; + return sigsuspend(&blocked); } long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index a69245b..fa54410 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -127,18 +127,8 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask) { sigset_t blocked; - - current->saved_sigmask = current->blocked; - - mask &= _BLOCKABLE; siginitset(&blocked, mask); - set_current_blocked(&blocked); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - - set_restore_sigmask(); - return -ERESTARTNOHAND; + return sigsuspend(&blocked); } asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr, diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 115eac4..b68ccad 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -478,18 +478,8 @@ asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) { sigset_t blocked; - - current->saved_sigmask = current->blocked; - - mask &= _BLOCKABLE; siginitset(&blocked, mask); - set_current_blocked(&blocked); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - - set_restore_sigmask(); - return -ERESTARTNOHAND; + return sigsuspend(&blocked); } asmlinkage int diff --git a/include/linux/signal.h b/include/linux/signal.h index 7987ce74..17046cc 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -252,6 +252,7 @@ extern int do_sigtimedwait(const sigset_t *, siginfo_t *, extern int sigprocmask(int, sigset_t *, sigset_t *); extern void set_current_blocked(const sigset_t *); extern int show_unhandled_signals; +extern int sigsuspend(sigset_t *); extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie); extern void block_sigmask(struct k_sigaction *ka, int signr); diff --git a/kernel/compat.c b/kernel/compat.c index d2c67aa..c28a306 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -1073,15 +1073,7 @@ asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t))) return -EFAULT; sigset_from_compat(&newset, &newset32); - sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP)); - - current->saved_sigmask = current->blocked; - set_current_blocked(&newset); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_restore_sigmask(); - return -ERESTARTNOHAND; + return sigsuspend(&newset); } #endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */ diff --git a/kernel/signal.c b/kernel/signal.c index 17afcaf..3ad220a 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -3236,6 +3236,21 @@ SYSCALL_DEFINE0(pause) #endif +#ifdef HAVE_SET_RESTORE_SIGMASK +int sigsuspend(sigset_t *set) +{ + sigdelsetmask(set, sigmask(SIGKILL)|sigmask(SIGSTOP)); + + current->saved_sigmask = current->blocked; + set_current_blocked(set); + + current->state = TASK_INTERRUPTIBLE; + schedule(); + set_restore_sigmask(); + return -ERESTARTNOHAND; +} +#endif + #ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND /** * sys_rt_sigsuspend - replace the signal mask for a value with the @@ -3253,15 +3268,7 @@ SYSCALL_DEFINE2(rt_sigsuspend, sigset_t __user *, unewset, size_t, sigsetsize) if (copy_from_user(&newset, unewset, sizeof(newset))) return -EFAULT; - sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP)); - - current->saved_sigmask = current->blocked; - set_current_blocked(&newset); - - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_restore_sigmask(); - return -ERESTARTNOHAND; + return sigsuspend(&newset); } #endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */ -- cgit v0.10.2 From ade7728b4e9aac4cc82117e3e35c5745b7d16037 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:58 +1000 Subject: parisc: use set_current_blocked() and block_sigmask() As described in e6fa16ab ("signal: sigprocmask() should do retarget_shared_pending()") the modification of current->blocked is incorrect as we need to check whether the signal we're about to block is pending in the shared queue. Also, use the new helper function introduced in commit 5e6292c0f28f ("signal: add block_sigmask() for adding sigmask to current->blocked") which centralises the code for updating current->blocked after successfully delivering a signal and reduces the amount of duplicate code across architectures. In the past some architectures got this code wrong, so using this helper function should stop that from happening again. Acked-by: Oleg Nesterov Acked-by: Kyle McMartin Cc: Helge Deller Cc: "James E.J. Bottomley" Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 12c1ed3..bd36152 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -131,10 +131,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) } sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); /* Good thing we saved the old gr[30], eh? */ #ifdef CONFIG_64BIT @@ -454,12 +451,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall)) return 0; - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + block_sigmask(ka, sig); tracehook_signal_handler(sig, info, ka, regs, test_thread_flag(TIF_SINGLESTEP) || -- cgit v0.10.2 From 7ebe0c5d7205a356532f2321e03d85bfd2443374 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:52 +1000 Subject: frv: use set_current_blocked() and block_sigmask() As described in e6fa16ab ("signal: sigprocmask() should do retarget_shared_pending()") the modification of current->blocked is incorrect as we need to check whether the signal we're about to block is pending in the shared queue. Also, use the new helper function introduced in commit 5e6292c0f28f ("signal: add block_sigmask() for adding sigmask to current->blocked") which centralises the code for updating current->blocked after successfully delivering a signal and reduces the amount of duplicate code across architectures. In the past some architectures got this code wrong, so using this helper function should stop that from happening again. Acked-by: Oleg Nesterov Acked-by: David Howells Cc: Al Viro Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index df957c7..b46a820 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -150,10 +150,7 @@ asmlinkage int sys_sigreturn(void) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(&frame->sc, &gr8)) goto badframe; @@ -176,10 +173,7 @@ asmlinkage int sys_rt_sigreturn(void) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(&frame->uc.uc_mcontext, &gr8)) goto badframe; @@ -466,15 +460,8 @@ static int handle_signal(unsigned long sig, siginfo_t *info, else ret = setup_frame(sig, ka, oldset); - if (ret == 0) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, - &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + if (ret == 0) + block_sigmask(ka, sig); return ret; -- cgit v0.10.2 From 8e3f9f65cb722d3663032b97ca76377b864f3835 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:11 +1000 Subject: blackfin: use set_current_blocked() and block_sigmask() As described in e6fa16ab ("signal: sigprocmask() should do retarget_shared_pending()") the modification of current->blocked is incorrect as we need to check whether the signal we're about to block is pending in the shared queue. Also, use the new helper function introduced in commit 5e6292c0f28f ("signal: add block_sigmask() for adding sigmask to current->blocked") which centralises the code for updating current->blocked after successfully delivering a signal and reduces the amount of duplicate code across architectures. In the past some architectures got this code wrong, so using this helper function should stop that from happening again. Acked-by: Oleg Nesterov Acked-by: Mike Frysinger Signed-off-by: Matt Fleming Acked-by: Michael Hennerich Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c index d536f35..05ece02 100644 --- a/arch/blackfin/kernel/signal.c +++ b/arch/blackfin/kernel/signal.c @@ -99,10 +99,7 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (rt_restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) goto badframe; @@ -266,15 +263,9 @@ handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, /* set up the stack frame */ ret = setup_rt_frame(sig, ka, info, oldset, regs); - if (ret == 0) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, - &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + if (ret == 0) + block_sigmask(ka, sig); + return ret; } -- cgit v0.10.2 From 9ae36796020998fcd07431934be6b160e9c7bfce Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:06 +1000 Subject: unicore32: use block_sigmask() Use the new helper function introduced in commit 5e6292c0f28f ("signal: add block_sigmask() for adding sigmask to current->blocked") which centralises the code for updating current->blocked after successfully delivering a signal and reduces the amount of duplicate code across architectures. In the past some architectures got this code wrong, so using this helper function should stop that from happening again. Acked-by: Oleg Nesterov Acked-by: Guan Xuetao Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c index 911b549..72d9531 100644 --- a/arch/unicore32/kernel/signal.c +++ b/arch/unicore32/kernel/signal.c @@ -370,10 +370,7 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, /* * Block the signal if we were successful. */ - sigorsets(&blocked, &tsk->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(&blocked, sig); - set_current_blocked(&blocked); + block_sigmask(ka, sig); return 0; } -- cgit v0.10.2 From 97c47bb70728c765d6cbf582759f9170fe152ded Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:06 +1000 Subject: h8300: use set_current_blocked() and block_sigmask() As described in e6fa16ab ("signal: sigprocmask() should do retarget_shared_pending()") the modification of current->blocked is incorrect as we need to check whether the signal we're about to block is pending in the shared queue. Also, use the new helper function introduced in commit 5e6292c0f28f ("signal: add block_sigmask() for adding sigmask to current->blocked") which centralises the code for updating current->blocked after successfully delivering a signal and reduces the amount of duplicate code across architectures. In the past some architectures got this code wrong, so using this helper function should stop that from happening again. Acked-by: Oleg Nesterov Cc: Yoshinori Sato Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index af842c3..cd63f5a 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c @@ -57,14 +57,13 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); asmlinkage int do_sigsuspend(struct pt_regs *regs) { old_sigset_t mask = regs->er3; - sigset_t saveset; + sigset_t saveset, blocked; - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); saveset = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + + mask &= _BLOCKABLE; + siginitset(&blocked, mask); + set_current_blocked(&blocked); regs->er0 = -EINTR; while (1) { @@ -90,11 +89,8 @@ do_rt_sigsuspend(struct pt_regs *regs) return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&newset); regs->er0 = -EINTR; while (1) { @@ -232,10 +228,7 @@ asmlinkage int do_sigreturn(unsigned long __unused,...) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(regs, &frame->sc, &er0)) goto badframe; @@ -260,10 +253,7 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused,...) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_unlock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_lock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &er0)) goto badframe; @@ -489,12 +479,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, else setup_frame(sig, ka, oldset, regs); - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + block_sigmask(ka, sig); } /* -- cgit v0.10.2 From 80c1dfa91c44665f2cecc1666050b2e8e04cef68 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:05 +1000 Subject: score: don't mask signals if we fail to setup signal stack If setup_rt_frame() returns -EFAULT then we must not block any signals in the current process. Acked-by: Oleg Nesterov Cc: Chen Liqin Cc: Lennox Wu Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c index aa57440..bf9e33e 100644 --- a/arch/score/kernel/signal.c +++ b/arch/score/kernel/signal.c @@ -272,12 +272,14 @@ static int handle_signal(unsigned long sig, siginfo_t *info, */ ret = setup_rt_frame(ka, regs, sig, oldset, info); - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + if (ret == 0) { + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked, sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } return ret; } -- cgit v0.10.2 From 4c3181bd3bde449d79b04e127b41ef02cade8005 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:05 +1000 Subject: score: use set_current_blocked() and block_sigmask() As described in e6fa16ab ("signal: sigprocmask() should do retarget_shared_pending()") the modification of current->blocked is incorrect as we need to check whether the signal we're about to block is pending in the shared queue. Also, use the new helper function introduced in commit 5e6292c0f28f ("signal: add block_sigmask() for adding sigmask to current->blocked") which centralises the code for updating current->blocked after successfully delivering a signal and reduces the amount of duplicate code across architectures. In the past some architectures got this code wrong, so using this helper function should stop that from happening again. Acked-by: Oleg Nesterov Cc: Chen Liqin Cc: Lennox Wu Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c index bf9e33e..5a5bd17 100644 --- a/arch/score/kernel/signal.c +++ b/arch/score/kernel/signal.c @@ -159,10 +159,7 @@ score_rt_sigreturn(struct pt_regs *regs) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext); if (sig < 0) @@ -272,14 +269,8 @@ static int handle_signal(unsigned long sig, siginfo_t *info, */ ret = setup_rt_frame(ka, regs, sig, oldset, info); - if (ret == 0) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + if (ret == 0) + block_sigmask(ka, sig); return ret; } -- cgit v0.10.2 From de8f2ddd69fc817b66138b36d656a2973d6afd8a Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:03 +1000 Subject: microblaze: don't reimplement force_sigsegv() Instead of open coding the sequence from force_sigsegv() just call it. This also fixes a bug because we were modifying ka->sa.sa_handler (which is a copy of sighand->action[]), whereas the intention of the code was to modify sighand->action[] directly. As the original code was working with a copy it had no effect on signal delivery. Acked-by: Oleg Nesterov Acked-by: Michal Simek Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 5996711..90de06d 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -270,9 +270,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } /* Handle restarting system calls */ -- cgit v0.10.2 From a12c3694aeb0321d5e6a50321c63881bd92a1bf2 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:04 +1000 Subject: microblaze: no need to reset handler if SA_ONESHOT get_signal_to_deliver() already resets the signal handler if SA_ONESHOT is set in ka->sa.sa_flags, there's no need to do it again in handle_signal(). Furthermore, because we were modifying ka->sa.sa_handler (which is a copy of sighand->action[]) instead of sighand->action[] the original code actually had no effect on signal delivery. Acked-by: Oleg Nesterov Acked-by: Michal Simek Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 90de06d..9e749c0 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -320,9 +320,6 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, else setup_rt_frame(sig, ka, NULL, oldset, regs); - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; - if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked, -- cgit v0.10.2 From bcb8c8d0b7131df1b5aad011db33e17f8def5d0b Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:04 +1000 Subject: microblaze: fix signal masking There are a couple of problems with the current signal code, 1. If we failed to setup the signal stack frame then we should not be masking any signals. 2. ka->sa.sa_mask is only added to the current blocked signals list if SA_NODEFER is set in ka->sa.sa_flags. If we successfully setup the signal frame and are going to run the handler then we must honour sa_mask. Acked-by: Oleg Nesterov Acked-by: Michal Simek Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 9e749c0..f2c13d5 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -169,7 +169,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, 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; @@ -267,10 +267,11 @@ 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; } /* Handle restarting system calls */ @@ -314,21 +315,25 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { + int ret; + /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) - setup_rt_frame(sig, ka, info, oldset, regs); + ret = setup_rt_frame(sig, ka, info, oldset, regs); else - setup_rt_frame(sig, ka, NULL, oldset, regs); + ret = setup_rt_frame(sig, ka, NULL, oldset, regs); + + if (ret) + return ret; - if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, - ¤t->blocked, &ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } - return 1; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + return 0; } /* @@ -369,7 +374,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall) /* Whee! Actually deliver the signal. */ if (in_syscall) handle_restart(regs, &ka, 1); - if (handle_signal(signr, &ka, &info, oldset, regs)) { + if (!handle_signal(signr, &ka, &info, oldset, regs)) { /* * A signal was successfully delivered; the saved * sigmask will have been stored in the signal frame, -- cgit v0.10.2 From 60c597513ee93fc6a0b7f2cb83d0aa67d4204cf1 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:05 +1000 Subject: microblaze: use set_current_blocked() and block_sigmask() As described in e6fa16ab ("signal: sigprocmask() should do retarget_shared_pending()") the modification of current->blocked is incorrect as we need to check whether the signal we're about to block is pending in the shared queue. Also, use the new helper function introduced in commit 5e6292c0f28f ("signal: add block_sigmask() for adding sigmask to current->blocked") which centralises the code for updating current->blocked after successfully delivering a signal and reduces the amount of duplicate code across architectures. In the past some architectures got this code wrong, so using this helper function should stop that from happening again. Acked-by: Oleg Nesterov Acked-by: Michal Simek Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index f2c13d5..99b9708 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -105,10 +105,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval)) goto badframe; @@ -326,12 +323,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, if (ret) return ret; - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + block_sigmask(ka, sig); return 0; } -- cgit v0.10.2 From 7a076e4ff07ffc2c219285ec57aed8bdde86cb37 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:03 +1000 Subject: ia64: use set_current_blocked() and block_sigmask() As described in e6fa16ab ("signal: sigprocmask() should do retarget_shared_pending()") the modification of current->blocked is incorrect as we need to check whether the signal we're about to block is pending in the shared queue. Also, use the new helper function introduced in commit 5e6292c0f28f ("signal: add block_sigmask() for adding sigmask to current->blocked") which centralises the code for updating current->blocked after successfully delivering a signal and reduces the amount of duplicate code across architectures. In the past some architectures got this code wrong, so using this helper function should stop that from happening again. Acked-by: Oleg Nesterov Cc: Tony Luck Cc: Fenghua Yu Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index 7bdafc8..7523501 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -201,13 +201,7 @@ ia64_rt_sigreturn (struct sigscratch *scr) goto give_sigsegv; sigdelsetmask(&set, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - { - current->blocked = set; - recalc_sigpending(); - } - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(sc, scr)) goto give_sigsegv; @@ -427,12 +421,7 @@ handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigse if (!setup_frame(sig, ka, info, oldset, scr)) return 0; - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + block_sigmask(ka, sig); /* * Let tracing know that we've done the handler setup. -- cgit v0.10.2 From f3b5e822739c70663aee8584b7993afe055431c9 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:00 +1000 Subject: cris: use set_current_blocked() and block_sigmask() As described in e6fa16ab ("signal: sigprocmask() should do retarget_shared_pending()") the modification of current->blocked is incorrect as we need to check whether the signal we're about to block is pending in the shared queue. Also, use the new helper function introduced in commit 5e6292c0f28f ("signal: add block_sigmask() for adding sigmask to current->blocked") which centralises the code for updating current->blocked after successfully delivering a signal and reduces the amount of duplicate code across architectures. In the past some architectures got this code wrong, so using this helper function should stop that from happening again. Acked-by: Oleg Nesterov Cc: Mikael Starvik Acked-by: Jesper Nilsson Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c index 170f497..df40fa8 100644 --- a/arch/cris/arch-v10/kernel/signal.c +++ b/arch/cris/arch-v10/kernel/signal.c @@ -177,10 +177,7 @@ asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(regs, &frame->sc)) goto badframe; @@ -216,10 +213,7 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; @@ -461,15 +455,9 @@ static inline int handle_signal(int canrestart, unsigned long sig, else ret = setup_frame(sig, ka, oldset, regs); - if (ret == 0) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, - &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + if (ret == 0) + block_sigmask(ka, sig); + return ret; } diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index e090832..b0a6cf4 100644 --- a/arch/cris/arch-v32/kernel/signal.c +++ b/arch/cris/arch-v32/kernel/signal.c @@ -168,12 +168,7 @@ sys_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp, goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - - current->blocked = set; - - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(regs, &frame->sc)) goto badframe; @@ -214,12 +209,7 @@ sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp, goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - - current->blocked = set; - - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; @@ -507,15 +497,8 @@ handle_signal(int canrestart, unsigned long sig, if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; - if (ret == 0) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, - &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + if (ret == 0) + block_sigmask(ka, sig); return ret; } -- cgit v0.10.2 From 00f35785fae2ae8a37b3a3dc1f2dc05e8f232bef Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:57:59 +1000 Subject: mn10300: use set_current_blocked() and block_sigmask() As described in e6fa16ab ("signal: sigprocmask() should do retarget_shared_pending()") the modification of current->blocked is incorrect as we need to check whether the signal we're about to block is pending in the shared queue. Also, use the new helper function introduced in commit 5e6292c0f28f ("signal: add block_sigmask() for adding sigmask to current->blocked") which centralises the code for updating current->blocked after successfully delivering a signal and reduces the amount of duplicate code across architectures. In the past some architectures got this code wrong, so using this helper function should stop that from happening again. Acked-by: Oleg Nesterov Acked-by: David Howells Cc: Koichi Yasutake Cc: Al Viro Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c index 50eb94a..890cf91 100644 --- a/arch/mn10300/kernel/signal.c +++ b/arch/mn10300/kernel/signal.c @@ -164,10 +164,7 @@ asmlinkage long sys_sigreturn(void) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(current_frame(), &frame->sc, &d0)) goto badframe; @@ -195,10 +192,7 @@ asmlinkage long sys_rt_sigreturn(void) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(current_frame(), &frame->uc.uc_mcontext, &d0)) goto badframe; @@ -468,15 +462,8 @@ static int handle_signal(int sig, else ret = setup_frame(sig, ka, oldset, regs); - if (ret == 0) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, - &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } + if (ret == 0) + block_sigmask(ka, sig); return ret; } -- cgit v0.10.2 From 3883e301bf05457d09ffc16c03ead6182ac3d732 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:57:59 +1000 Subject: m32r: use set_current_blocked() and block_sigmask() As described in e6fa16ab ("signal: sigprocmask() should do retarget_shared_pending()") the modification of current->blocked is incorrect as we need to check whether the signal we're about to block is pending in the shared queue. Also, use the new helper function introduced in commit 5e6292c0f28f ("signal: add block_sigmask() for adding sigmask to current->blocked") which centralises the code for updating current->blocked after successfully delivering a signal and reduces the amount of duplicate code across architectures. In the past some architectures got this code wrong, so using this helper function should stop that from happening again. Acked-by: Oleg Nesterov Cc: Hirokazu Takata Cc: Al Viro Cc: Kyle McMartin Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index a08697f..f54d969 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -112,10 +112,7 @@ sys_rt_sigreturn(unsigned long r0, unsigned long r1, goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &result)) goto badframe; @@ -300,12 +297,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, 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); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + block_sigmask(ka, sig); return 0; } -- cgit v0.10.2 From e1b1fd79a04396d5ec971e9e4d4711b5a58ad7e3 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:57:57 +1000 Subject: avr32: don't mask signals in the error path The current handle_signal() implementation is broken - it will mask signals if we fail to setup the signal stack frame, which isn't the desired behaviour, we should only be masking signals if we succeed in setting up the stack frame. It looks like this code was copied from the old (broken) arm implementation but wasn't updated when the arm code was fixed in commit a6c61e9dfdd0 ("[ARM] 3168/1: Update ARM signal delivery and masking"). Cc: Hans-Christian Egtvedt Acked-by: Havard Skinnemoen Acked-by: Oleg Nesterov Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 64f886f..9c075e1 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -238,22 +238,21 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, */ ret |= !valid_user_regs(regs); + if (ret != 0) { + force_sigsegv(sig, current); + return; + } + /* - * Block the signal if we were unsuccessful. + * Block the signal if we were successful. */ - if (ret != 0 || !(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, - &ka->sa.sa_mask); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, + &ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - } - - if (ret == 0) - return; - - force_sigsegv(sig, current); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } /* -- cgit v0.10.2 From 49209590cb1cdd30b35edd65535184e39bfbab99 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 11 May 2012 10:57:58 +1000 Subject: avr32: use set_current_blocked() in handle_signal/sys_rt_sigreturn It is wrong to change ->blocked directly, see e6fa16ab. Change handle_signal() and sys_rt_sigreturn() to use the right helper, set_current_blocked(). Cc: Hans-Christian Egtvedt Acked-by: Havard Skinnemoen Reviewed-by: Matt Fleming Signed-off-by: Oleg Nesterov Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 9c075e1..06f4293 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -87,10 +87,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&set); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; @@ -226,6 +223,7 @@ static inline void handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs, int syscall) { + sigset_t blocked; int ret; /* @@ -246,13 +244,10 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, /* * Block the signal if we were successful. */ - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, - &ka->sa.sa_mask); + sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask); if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + sigaddset(&blocked, sig); + set_current_blocked(&blocked); } /* -- cgit v0.10.2 From 54bbf3e3a9af5e3c439766fda444fb0673a1a721 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:57:58 +1000 Subject: avr32: use block_sigmask() Use the new helper function introduced in commit 5e6292c0f28f ("signal: add block_sigmask() for adding sigmask to current->blocked") which centralises the code for updating current->blocked after successfully delivering a signal and reduces the amount of duplicate code across architectures. In the past some architectures got this code wrong, so using this helper function should stop that from happening again. Acked-by: Oleg Nesterov Cc: Hans-Christian Egtvedt Cc: Havard Skinnemoen Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 06f4293..feeb77b 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -223,7 +223,6 @@ static inline void handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs, int syscall) { - sigset_t blocked; int ret; /* @@ -244,10 +243,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, /* * Block the signal if we were successful. */ - sigorsets(&blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(&blocked, sig); - set_current_blocked(&blocked); + block_sigmask(ka, sig); } /* -- cgit v0.10.2 From 3334bf12480f10377e44d932baf53f34ec737f8b Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 11 May 2012 10:59:08 +1000 Subject: hexagon: do_notify_resume() needs tracehook_notify_resume() arch/hexagon/kernel/signal.c:do_notify_resume() forgets to call tracehook_notify_resume() if TIF_NOTIFY_RESUME is set. Signed-off-by: Oleg Nesterov Acked-by: Richard Kuo Cc: David Howells Cc: Thomas Gleixner Cc: Linus Torvalds Cc: Alexander Gordeev Cc: Chris Zankel Cc: David Smith Cc: "Frank Ch. Eigler" Cc: Geert Uytterhoeven Cc: Larry Woodman Cc: Peter Zijlstra Cc: Tejun Heo Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c index ecbab34..ab5f5ad 100644 --- a/arch/hexagon/kernel/signal.c +++ b/arch/hexagon/kernel/signal.c @@ -272,6 +272,7 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); if (current->replacement_session_keyring) key_replace_session_keyring(); } -- cgit v0.10.2 From 43a35995562495bd70a87b5d3a2e820036ee6597 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:57:59 +1000 Subject: m68k: use set_current_blocked() and block_sigmask() As described in e6fa16ab ("signal: sigprocmask() should do retarget_shared_pending()") the modification of current->blocked is incorrect as we need to check whether the signal we're about to block is pending in the shared queue. Also, use the new helper function introduced in commit 5e6292c0f28f ("signal: add block_sigmask() for adding sigmask to current->blocked") which centralises the code for updating current->blocked after successfully delivering a signal and reduces the amount of duplicate code across architectures. In the past some architectures got this code wrong, so using this helper function should stop that from happening again. Acked-by: Oleg Nesterov Cc: Geert Uytterhoeven Acked-by: Greg Ungerer Signed-off-by: Matt Fleming Signed-off-by: Andrew Morton Signed-off-by: Al Viro diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index 8186982..d8f6960 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c @@ -795,8 +795,7 @@ asmlinkage int do_sigreturn(unsigned long __unused) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - current->blocked = set; - recalc_sigpending(); + set_current_blocked(&set); if (restore_sigcontext(regs, &frame->sc, frame + 1)) goto badframe; @@ -821,8 +820,7 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - current->blocked = set; - recalc_sigpending(); + set_current_blocked(&set); if (rt_restore_ucontext(regs, sw, &frame->uc)) goto badframe; @@ -1141,10 +1139,7 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, if (err) return; - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked,sig); - recalc_sigpending(); + block_sigmask(ka, sig); if (test_thread_flag(TIF_DELAYED_TRACE)) { regs->sr &= ~0x8000; -- cgit v0.10.2 From 85a847ffad1d4ee94590db25bad444d18a8db263 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 03:15:40 -0400 Subject: parisc: resetting ->restart_block.fn needs to be done on rt_sigreturn() Signed-off-by: Al Viro diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index bd36152..4b9cb0d 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -109,6 +109,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall) sigframe_size = PARISC_RT_SIGFRAME_SIZE32; #endif + current_thread_info()->restart_block.fn = do_no_restart_syscall; /* Unwind the user stack to get the rt_sigframe structure. */ frame = (struct rt_sigframe __user *) @@ -466,8 +467,6 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) /* Check the return code */ switch (regs->gr[28]) { case -ERESTART_RESTARTBLOCK: - current_thread_info()->restart_block.fn = - do_no_restart_syscall; case -ERESTARTNOHAND: DBG(1,"ERESTARTNOHAND: returning -EINTR\n"); regs->gr[28] = -EINTR; -- cgit v0.10.2 From 2a3fdc117cdd664814d7374941698729e47fea95 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 03:30:18 -0400 Subject: c6x: ->restart_block.fn needs to be reset on rt_sigreturn Signed-off-by: Al Viro diff --git a/arch/c6x/kernel/signal.c b/arch/c6x/kernel/signal.c index 3b5a050..cf37478 100644 --- a/arch/c6x/kernel/signal.c +++ b/arch/c6x/kernel/signal.c @@ -69,6 +69,9 @@ asmlinkage int do_rt_sigreturn(struct pt_regs *regs) struct rt_sigframe __user *frame; sigset_t set; + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + /* * Since we stacked the signal on a dword boundary, * 'sp' should be dword aligned here. If it's -- cgit v0.10.2 From ef9b122f322d9d9550160ca33a6efbd759a43b55 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 03:31:24 -0400 Subject: hexagon: ->restart_block.fn needs to be reset on rt_sigreturn Signed-off-by: Al Viro diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c index ab5f5ad..434866e 100644 --- a/arch/hexagon/kernel/signal.c +++ b/arch/hexagon/kernel/signal.c @@ -294,6 +294,9 @@ asmlinkage int sys_rt_sigreturn(void) struct rt_sigframe __user *frame; sigset_t blocked; + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + frame = (struct rt_sigframe __user *)pt_psp(regs); if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; -- cgit v0.10.2 From 58e4257bc6336db015673a8cb598bd6cdbecf6d1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 03:32:18 -0400 Subject: microblaze: ->restart_block.fn needs to be reset on rt_sigreturn Signed-off-by: Al Viro diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 99b9708..fbdb026 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -98,6 +98,9 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) sigset_t set; int rval; + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; -- cgit v0.10.2 From f2ccfb3e565f51f1063d68f119d5b42a7f5fd984 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 03:33:45 -0400 Subject: score: ->restart_block.fn needs to be reset on rt_sigreturn Signed-off-by: Al Viro diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c index 5a5bd17..c3fded7 100644 --- a/arch/score/kernel/signal.c +++ b/arch/score/kernel/signal.c @@ -152,6 +152,9 @@ score_rt_sigreturn(struct pt_regs *regs) stack_t st; int sig; + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + frame = (struct rt_sigframe __user *) regs->regs[0]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; -- cgit v0.10.2 From 188f677f84e935f83e3d539d6e8808006f6ac62f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 03:35:28 -0400 Subject: xtensa: ->restart_block.fn needs to be reset on rt_sigreturn Signed-off-by: Al Viro diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index d78869a..44e9329 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -248,6 +248,9 @@ asmlinkage long xtensa_rt_sigreturn(long a0, long a1, long a2, long a3, sigset_t set; int ret; + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + if (regs->depc > 64) panic("rt_sigreturn in double exception!\n"); -- cgit v0.10.2 From 446cdd13275bfa38b858a1e99dbd61c07c9767c0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 03:36:05 -0400 Subject: avr32: ->restart_block.fn needs to be reset on rt_sigreturn Signed-off-by: Al Viro diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index feeb77b..a4855ae 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -77,6 +77,9 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) struct rt_sigframe __user *frame; sigset_t set; + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + frame = (struct rt_sigframe __user *)regs->sp; pr_debug("SIG return: frame = %p\n", frame); -- cgit v0.10.2 From 9ccc9c75c9117d18a9b1f71a21f0066b1eb9db6f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 00:59:07 -0400 Subject: xtensa: switch to generic rt_sigsuspend(2) Signed-off-by: Al Viro diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h index efcf33b..fc289f7 100644 --- a/arch/xtensa/include/asm/syscall.h +++ b/arch/xtensa/include/asm/syscall.h @@ -15,8 +15,6 @@ asmlinkage long xtensa_clone(unsigned long, unsigned long, struct pt_regs*); asmlinkage long xtensa_ptrace(long, long, long, long); asmlinkage long xtensa_sigreturn(struct pt_regs*); asmlinkage long xtensa_rt_sigreturn(struct pt_regs*); -asmlinkage long xtensa_sigsuspend(struct pt_regs*); -asmlinkage long xtensa_rt_sigsuspend(struct pt_regs*); asmlinkage long xtensa_sigaction(int, const struct old_sigaction*, struct old_sigaction*); asmlinkage long xtensa_sigaltstack(struct pt_regs *regs); diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h index 798ee6d..bc7e005 100644 --- a/arch/xtensa/include/asm/unistd.h +++ b/arch/xtensa/include/asm/unistd.h @@ -507,7 +507,7 @@ __SYSCALL(229, sys_rt_sigtimedwait, 4) #define __NR_rt_sigqueueinfo 230 __SYSCALL(230, sys_rt_sigqueueinfo, 3) #define __NR_rt_sigsuspend 231 -__SYSCALL(231, xtensa_rt_sigsuspend, 2) +__SYSCALL(231, sys_rt_sigsuspend, 2) /* Message */ diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 6223f33..b1bb6d7 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S @@ -418,7 +418,6 @@ common_exception_return: movi a4, do_signal # int do_signal(struct pt_regs*, sigset_t*) mov a6, a1 - movi a7, 0 callx4 a4 j 1b diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index 44e9329..bb00cc4 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -31,8 +31,6 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); - extern struct task_struct *coproc_owners[]; struct rt_sigframe @@ -429,37 +427,6 @@ give_sigsegv: return -EFAULT; } -/* - * Atomically swap in the new signal mask, and wait for a signal. - */ - -asmlinkage long xtensa_rt_sigsuspend(sigset_t __user *unewset, - size_t sigsetsize, - long a2, long a3, long a4, long a5, - struct pt_regs *regs) -{ - sigset_t saveset, 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, ~_BLOCKABLE); - saveset = current->blocked; - set_current_blocked(&newset); - - regs->areg[2] = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(regs, &saveset)) - return -EINTR; - } -} - asmlinkage long xtensa_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, long a2, long a3, long a4, long a5, @@ -479,19 +446,22 @@ asmlinkage long xtensa_sigaltstack(const stack_t __user *uss, * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -int do_signal(struct pt_regs *regs, sigset_t *oldset) +void do_signal(struct pt_regs *regs) { siginfo_t info; int signr; struct k_sigaction ka; + sigset_t oldset; if (!user_mode(regs)) - return 0; + return; if (try_to_freeze()) goto no_signal; - if (!oldset) + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else oldset = ¤t->blocked; task_pt_regs(current)->icountlevel = 0; @@ -535,13 +505,14 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) /* Set up the stack frame */ ret = setup_frame(signr, &ka, &info, oldset, regs); if (ret) - return ret; + return; + clear_thread_flag(TIF_RESTORE_SIGMASK); block_sigmask(&ka, signr); if (current->ptrace & PT_SINGLESTEP) task_pt_regs(current)->icountlevel = 1; - return 1; + return; } no_signal: @@ -561,8 +532,13 @@ no_signal: break; } } + + /* If there's no signal to deliver, we just restore the saved mask. */ + if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK)) + set_current_blocked(¤t->saved_sigmask); + if (current->ptrace & PT_SINGLESTEP) task_pt_regs(current)->icountlevel = 1; - return 0; + return; } -- cgit v0.10.2 From 9ef461adf9875a0fcaafe4d152a7557740fa1a25 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 01:16:34 -0400 Subject: sh: switch to saved_sigmask-based sigsuspend()/rt_sigsuspend() Complete the move of sh64 to it, trim the crap from prototypes, tidy up a bit. Infrastructure in do_signal() had already been there, in signal_64 as well as in signal_32 (where it was already used). Signed-off-by: Al Viro diff --git a/arch/sh/include/asm/syscalls_32.h b/arch/sh/include/asm/syscalls_32.h index ae717e3..6c1fa55 100644 --- a/arch/sh/include/asm/syscalls_32.h +++ b/arch/sh/include/asm/syscalls_32.h @@ -23,9 +23,7 @@ asmlinkage int sys_execve(const char __user *ufilename, const char __user *const __user *uargv, const char __user *const __user *uenvp, unsigned long r7, struct pt_regs __regs); -asmlinkage int sys_sigsuspend(old_sigset_t mask, unsigned long r5, - unsigned long r6, unsigned long r7, - struct pt_regs __regs); +asmlinkage int sys_sigsuspend(old_sigset_t mask); asmlinkage int sys_sigaction(int sig, const struct old_sigaction __user *act, struct old_sigaction __user *oact); asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, diff --git a/arch/sh/include/asm/unistd.h b/arch/sh/include/asm/unistd.h index a42a561..e800a38 100644 --- a/arch/sh/include/asm/unistd.h +++ b/arch/sh/include/asm/unistd.h @@ -1,13 +1,11 @@ #ifdef __KERNEL__ # ifdef CONFIG_SUPERH32 - # include "unistd_32.h" -# define __ARCH_WANT_SYS_RT_SIGSUSPEND - # else # include "unistd_64.h" # endif +# define __ARCH_WANT_SYS_RT_SIGSUSPEND # define __ARCH_WANT_IPC_PARSE_VERSION # define __ARCH_WANT_OLD_READDIR # define __ARCH_WANT_OLD_STAT diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 46c9f9b..04d776f 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c @@ -53,9 +53,7 @@ struct fdpic_func_descriptor { * Atomically swap in the new signal mask, and wait for a signal. */ asmlinkage int -sys_sigsuspend(old_sigset_t mask, - unsigned long r5, unsigned long r6, unsigned long r7, - struct pt_regs __regs) +sys_sigsuspend(old_sigset_t mask) { sigset_t blocked; siginitset(&blocked, mask); diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index 3c9a6f7..8f6ed23 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c @@ -83,11 +83,12 @@ handle_syscall_restart(struct pt_regs *regs, struct sigaction *sa) * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -static int do_signal(struct pt_regs *regs, sigset_t *oldset) +static void do_signal(struct pt_regs *regs) { siginfo_t info; int signr; struct k_sigaction ka; + sigset_t *oldset; /* * We want the common case to go fast, which @@ -96,11 +97,11 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) * if so. */ if (!user_mode(regs)) - return 1; + return; if (current_thread_info()->status & TS_RESTORE_SIGMASK) oldset = ¤t->saved_sigmask; - else if (!oldset) + else oldset = ¤t->blocked; signr = get_signal_to_deliver(&info, &ka, regs, 0); @@ -118,7 +119,7 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) tracehook_signal_handler(signr, &info, &ka, regs, test_thread_flag(TIF_SINGLESTEP)); - return 1; + return; } } @@ -147,71 +148,18 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); } - return 0; + return; } /* * Atomically swap in the new signal mask, and wait for a signal. */ asmlinkage int -sys_sigsuspend(old_sigset_t mask, - unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7, - struct pt_regs * regs) +sys_sigsuspend(old_sigset_t mask) { - sigset_t saveset, blocked; - - saveset = current->blocked; - - mask &= _BLOCKABLE; + sigset_t blocked; siginitset(&blocked, mask); - set_current_blocked(&blocked); - - REF_REG_RET = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - set_restore_sigmask(); - regs->pc += 4; /* because sys_sigreturn decrements the pc */ - if (do_signal(regs, &saveset)) { - /* pc now points at signal handler. Need to decrement - it because entry.S will increment it. */ - regs->pc -= 4; - return -EINTR; - } - } -} - -asmlinkage int -sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, - unsigned long r4, unsigned long r5, unsigned long r6, - unsigned long r7, - struct pt_regs * regs) -{ - sigset_t saveset, 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, ~_BLOCKABLE); - saveset = current->blocked; - set_current_blocked(&newset); - - REF_REG_RET = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - regs->pc += 4; /* because sys_sigreturn decrements the pc */ - if (do_signal(regs, &saveset)) { - /* pc now points at signal handler. Need to decrement - it because entry.S will increment it. */ - regs->pc -= 4; - return -EINTR; - } - } + return sigsuspend(&blocked); } asmlinkage int @@ -732,7 +680,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) { if (thread_info_flags & _TIF_SIGPENDING) - do_signal(regs, 0); + do_signal(regs); if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); -- cgit v0.10.2 From 8b6c3309c94b7296614d7783eb259555a6be6f7e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 21 Apr 2012 22:42:11 -0400 Subject: h8300: don't change blocked signals' mask if setting frame up fails Signed-off-by: Al Viro diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index cd63f5a..78e9b65 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c @@ -304,7 +304,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) return (void *)((usp - frame_size) & -8UL); } -static void setup_frame (int sig, struct k_sigaction *ka, +static int setup_frame (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) { struct sigframe *frame; @@ -365,13 +365,14 @@ static void setup_frame (int sig, struct k_sigaction *ka, regs->er1 = (unsigned long)&(frame->sc); regs->er5 = current->mm->start_data; /* GOT base */ - return; + return 0; give_sigsegv: force_sigsegv(sig, current); + return -EFAULT; } -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 *frame; @@ -440,10 +441,11 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, regs->er2 = (unsigned long)&frame->uc; regs->er5 = current->mm->start_data; /* GOT base */ - return; + return 0; give_sigsegv: force_sigsegv(sig, current); + return -EFAULT; } /* @@ -453,6 +455,7 @@ static void handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs * regs) { + int ret; /* are we from a system call? */ if (regs->orig_er0 >= 0) { switch (regs->er0) { @@ -475,11 +478,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, /* set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) - setup_rt_frame(sig, ka, info, oldset, regs); + ret = setup_rt_frame(sig, ka, info, oldset, regs); else - setup_frame(sig, ka, oldset, regs); + ret = setup_frame(sig, ka, oldset, regs); - block_sigmask(ka, sig); + if (!ret) + block_sigmask(ka, sig); } /* -- cgit v0.10.2 From 7ae4e32a65148353db3458e3eb87117f25620ac5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 01:30:05 -0400 Subject: h8300: switch to saved_sigmask-based sigsuspend/rt_sigsuspend Signed-off-by: Al Viro diff --git a/arch/h8300/include/asm/unistd.h b/arch/h8300/include/asm/unistd.h index 2c3f8e6..7185113 100644 --- a/arch/h8300/include/asm/unistd.h +++ b/arch/h8300/include/asm/unistd.h @@ -356,6 +356,7 @@ #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK #define __ARCH_WANT_SYS_RT_SIGACTION +#define __ARCH_WANT_SYS_RT_SIGSUSPEND /* * "Conditional" syscalls diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index 78e9b65..b5e360a 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c @@ -49,56 +49,15 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); - /* * Atomically swap in the new signal mask, and wait for a signal. */ -asmlinkage int do_sigsuspend(struct pt_regs *regs) -{ - old_sigset_t mask = regs->er3; - sigset_t saveset, blocked; - - saveset = current->blocked; - - mask &= _BLOCKABLE; - siginitset(&blocked, mask); - set_current_blocked(&blocked); - - regs->er0 = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(regs, &saveset)) - return -EINTR; - } -} - asmlinkage int -do_rt_sigsuspend(struct pt_regs *regs) +sys_sigsuspend(int unused1, int unused2, old_sigset_t mask) { - sigset_t *unewset = (sigset_t *)regs->er1; - size_t sigsetsize = (size_t)regs->er2; - sigset_t saveset, 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, ~_BLOCKABLE); - - saveset = current->blocked; - set_current_blocked(&newset); - - regs->er0 = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(regs, &saveset)) - return -EINTR; - } + sigset_t blocked; + siginitset(&blocked, mask); + return sigsuspend(&blocked); } asmlinkage int @@ -482,8 +441,10 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, else ret = setup_frame(sig, ka, oldset, regs); - if (!ret) + if (!ret) { block_sigmask(ka, sig); + clear_thread_flag(TIF_RESTORE_SIGMASK); + } } /* @@ -491,11 +452,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset) +statis void do_signal(struct pt_regs *regs) { siginfo_t info; int signr; struct k_sigaction ka; + sigset_t *oldset; /* * We want the common case to go fast, which @@ -504,21 +466,23 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset) * if so. */ if ((regs->ccr & 0x10)) - return 1; + return; if (try_to_freeze()) goto no_signal; current->thread.esp0 = (unsigned long) regs; - 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); if (signr > 0) { /* Whee! Actually deliver the signal. */ handle_signal(signr, &info, &ka, oldset, regs); - return 1; + return; } no_signal: /* Did we come from a system call? */ @@ -535,13 +499,16 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset) regs->pc -= 2; } } - return 0; + + /* If there's no signal to deliver, we just restore the saved mask. */ + if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK)) + set_current_blocked(¤t->saved_sigmask); } asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) { - if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) - do_signal(regs, NULL); + if (thread_info_flags & _TIF_SIGPENDING) + do_signal(regs); if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); diff --git a/arch/h8300/kernel/syscalls.S b/arch/h8300/kernel/syscalls.S index 4be2ea2..9d77e71 100644 --- a/arch/h8300/kernel/syscalls.S +++ b/arch/h8300/kernel/syscalls.S @@ -343,12 +343,6 @@ SYMBOL_NAME_LABEL(sys_call_table) SYMBOL_NAME_LABEL(sys_clone) call_sp h8300_clone -SYMBOL_NAME_LABEL(sys_sigsuspend) - call_sp do_sigsuspend - -SYMBOL_NAME_LABEL(sys_rt_sigsuspend) - call_sp do_rt_sigsuspend - SYMBOL_NAME_LABEL(sys_sigreturn) call_sp do_sigreturn -- cgit v0.10.2 From a4e075c43e7fd9af769b28b7cb454615f61e2698 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 May 2012 09:46:55 -0400 Subject: cris: SA_ONESHOT handling is done by get_signal_to_deliver() ... and resetting sa_handler in local copy filled by get_signal_to_deliver() is obviously pointless anyway. Signed-off-by: Al Viro diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index b0a6cf4..5590578 100644 --- a/arch/cris/arch-v32/kernel/signal.c +++ b/arch/cris/arch-v32/kernel/signal.c @@ -494,9 +494,6 @@ handle_signal(int canrestart, unsigned long sig, else ret = setup_frame(sig, ka, oldset, regs); - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; - if (ret == 0) block_sigmask(ka, sig); -- cgit v0.10.2 From ae28b38ca14122b990a83bf4ef95a12889cc6b92 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 00:28:50 -0400 Subject: microblaze: bury sys_rt_sigsuspend_wrapper in nommu case too It's been a dead code since commit 571202f50fad0aeb36661c79de9beed052347df8 Author: Michal Simek Date: Fri Dec 11 12:54:04 2009 +0100 microblaze: Remove rt_sigsuspend wrapper Generic rt_sigsuspend syscalls doesn't need any asm wrapper. but that commit has only removed it from entry.S, missing one in entry-nommu.S. Signed-off-by: Al Viro diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S index 34b526f..f104d27 100644 --- a/arch/microblaze/kernel/entry-nommu.S +++ b/arch/microblaze/kernel/entry-nommu.S @@ -569,10 +569,6 @@ sys_rt_sigreturn_wrapper: brid sys_rt_sigreturn addk r5, r1, r0 -sys_rt_sigsuspend_wrapper: - brid sys_rt_sigsuspend - addk r7, r1, r0 - /* Interrupt vector table */ .section .init.ivt, "ax" .org 0x0 -- cgit v0.10.2 From fe49c1cebf054d5c797ecd6b91d5bf96d4295fe4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 May 2012 09:52:37 -0400 Subject: avr32: need to clear RESTORE_SIGMASK on successful signal delivery Signed-off-by: Al Viro diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index a4855ae..ae386c3 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -247,6 +247,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, * Block the signal if we were successful. */ block_sigmask(ka, sig); + clear_thread_flag(TIF_RESTORE_SIGMASK); } /* -- cgit v0.10.2 From 5d71c55bdb020561a9d44c8453ca2a3ca524ea35 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 21 Apr 2012 21:32:46 -0400 Subject: blackfin: don't open-code force_sigsegv() ... especially since we don't have the right k_sigaction here, so resetting sa_handler won't work. Signed-off-by: Al Viro diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c index 05ece02..e5bbc1a 100644 --- a/arch/blackfin/kernel/signal.c +++ b/arch/blackfin/kernel/signal.c @@ -210,9 +210,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info, return 0; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); return -EFAULT; } -- cgit v0.10.2 From 6eef019002e61abdc5e4384e4154d73c9f56d2bc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 21 Apr 2012 21:35:56 -0400 Subject: cris: don't open-code force_sigsegv() Signed-off-by: Al Viro diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index 5590578..a45efc7 100644 --- a/arch/cris/arch-v32/kernel/signal.c +++ b/arch/cris/arch-v32/kernel/signal.c @@ -345,10 +345,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, return 0; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); return -EFAULT; } @@ -432,10 +429,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, return 0; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); return -EFAULT; } -- cgit v0.10.2 From cf4a0ce45c06f79f800f6d8747618901e3a6a8ad Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 21 Apr 2012 21:39:54 -0400 Subject: score: don't open-code force_sigsegv() Signed-off-by: Al Viro diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c index c3fded7..a087ad8 100644 --- a/arch/score/kernel/signal.c +++ b/arch/score/kernel/signal.c @@ -236,9 +236,7 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, return 0; give_sigsegv: - if (signr == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(signr, current); return -EFAULT; } -- cgit v0.10.2 From cbdfb9ff551cbe3e002387e7fb0256f384c26e91 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 02:34:42 -0400 Subject: alpha: tidy signal delivery up * move force_sigsegv() (from setup...frame()) and clearing RESTART_SIGMASK (from do_signal()) into hanlde_signal() * get rid of handle_signal() return value and oldset argument * checking for TIF_SIGPENDING is enough; set_restart_sigmask() sets this one as well. Signed-off-by: Al Viro diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 74b05e6..10ab2d7 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -34,9 +34,6 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage void ret_from_sys_call(void); -static void do_signal(struct pt_regs *, struct switch_stack *, - unsigned long, unsigned long); - /* * The OSF/1 sigprocmask calling sequence is different from the @@ -367,11 +364,11 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, oldsp = rdusp(); frame = get_sigframe(ka, oldsp, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto give_sigsegv; + return -EFAULT; err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp); if (err) - goto give_sigsegv; + return -EFAULT; /* Set up to return from userspace. If provided, use a stub already in userspace. */ @@ -387,7 +384,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, /* Check that everything was written properly. */ if (err) - goto give_sigsegv; + return err; /* "Return" to the handler */ regs->r26 = r26; @@ -401,12 +398,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->pc, regs->r26); #endif - return 0; - -give_sigsegv: - force_sigsegv(sig, current); - return -EFAULT; } static int @@ -419,7 +411,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, oldsp = rdusp(); frame = get_sigframe(ka, oldsp, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto give_sigsegv; + return -EFAULT; err |= copy_siginfo_to_user(&frame->info, info); @@ -434,7 +426,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, set->sig[0], oldsp); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); if (err) - goto give_sigsegv; + return -EFAULT; /* Set up to return from userspace. If provided, use a stub already in userspace. */ @@ -450,7 +442,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, } if (err) - goto give_sigsegv; + return -EFAULT; /* "Return" to the handler */ regs->r26 = r26; @@ -466,31 +458,37 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, #endif return 0; - -give_sigsegv: - force_sigsegv(sig, current); - return -EFAULT; } /* * OK, we're invoking a handler. */ -static inline int +static inline void handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *oldset, struct pt_regs * regs, struct switch_stack *sw) + struct pt_regs * regs, struct switch_stack *sw) { + sigset_t *oldset = ¤t->blocked; int ret; + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + if (ka->sa.sa_flags & SA_SIGINFO) ret = setup_rt_frame(sig, ka, info, oldset, regs, sw); else ret = setup_frame(sig, ka, oldset, regs, sw); - if (ret == 0) - block_sigmask(ka, sig); - - return ret; + if (ret) { + force_sigsegv(sig, current); + return; + } + block_sigmask(ka, sig); + /* A signal was successfully delivered, and the + saved sigmask was stored on the signal frame, + and will be restored by sigreturn. So we can + simply clear the restore sigmask flag. */ + clear_thread_flag(TIF_RESTORE_SIGMASK); } static inline void @@ -538,12 +536,6 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw, int signr; unsigned long single_stepping = ptrace_cancel_bpt(current); struct k_sigaction ka; - sigset_t *oldset; - - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - oldset = ¤t->saved_sigmask; - else - oldset = ¤t->blocked; /* This lets the debugger run, ... */ signr = get_signal_to_deliver(&info, &ka, regs, NULL); @@ -555,14 +547,7 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw, /* Whee! Actually deliver the signal. */ if (r0) syscall_restart(r0, r19, regs, &ka); - if (handle_signal(signr, &ka, &info, oldset, regs, sw) == 0) { - /* A signal was successfully delivered, and the - saved sigmask was stored on the signal frame, - and will be restored by sigreturn. So we can - simply clear the restore sigmask flag. */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - clear_thread_flag(TIF_RESTORE_SIGMASK); - } + handle_signal(signr, &ka, &info, regs, sw); if (single_stepping) ptrace_set_bpt(current); /* re-set bpt */ return; @@ -587,10 +572,8 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw, } /* If there's no signal to deliver, we just restore the saved mask. */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) { - clear_thread_flag(TIF_RESTORE_SIGMASK); - sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); - } + if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK)) + set_current_blocked(¤t->saved_sigmask); if (single_stepping) ptrace_set_bpt(current); /* re-set breakpoint */ @@ -601,7 +584,7 @@ do_notify_resume(struct pt_regs *regs, struct switch_stack *sw, unsigned long thread_info_flags, unsigned long r0, unsigned long r19) { - if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) + if (thread_info_flags & _TIF_SIGPENDING) do_signal(regs, sw, r0, r19); if (thread_info_flags & _TIF_NOTIFY_RESUME) { -- cgit v0.10.2 From b1175ed2234235276f4a2256f72a277b85320cf9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 16:19:57 -0400 Subject: xtensa: xtensa_sigaction doesn't exist ... and struct old_sigaction never used Signed-off-by: Al Viro diff --git a/arch/xtensa/include/asm/signal.h b/arch/xtensa/include/asm/signal.h index 633ba73..7f201b9 100644 --- a/arch/xtensa/include/asm/signal.h +++ b/arch/xtensa/include/asm/signal.h @@ -120,13 +120,6 @@ typedef void (*__sighandler_t)(int); #define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ #ifdef __KERNEL__ -struct old_sigaction { - __sighandler_t sa_handler; - old_sigset_t sa_mask; - unsigned long sa_flags; - void (*sa_restorer)(void); -}; - struct sigaction { __sighandler_t sa_handler; unsigned long sa_flags; diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h index fc289f7..0b9f2e1 100644 --- a/arch/xtensa/include/asm/syscall.h +++ b/arch/xtensa/include/asm/syscall.h @@ -15,8 +15,6 @@ asmlinkage long xtensa_clone(unsigned long, unsigned long, struct pt_regs*); asmlinkage long xtensa_ptrace(long, long, long, long); asmlinkage long xtensa_sigreturn(struct pt_regs*); asmlinkage long xtensa_rt_sigreturn(struct pt_regs*); -asmlinkage long xtensa_sigaction(int, const struct old_sigaction*, - struct old_sigaction*); asmlinkage long xtensa_sigaltstack(struct pt_regs *regs); asmlinkage long sys_rt_sigaction(int, const struct sigaction __user *, -- cgit v0.10.2 From fe2eff8b87a3b33efd1bb30bb775cef71eaca34d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 16:20:52 -0400 Subject: m32r: struct old_sigaction is never used Signed-off-by: Al Viro diff --git a/arch/m32r/include/asm/signal.h b/arch/m32r/include/asm/signal.h index b2eeb0d..ea5f95e 100644 --- a/arch/m32r/include/asm/signal.h +++ b/arch/m32r/include/asm/signal.h @@ -110,13 +110,6 @@ typedef unsigned long sigset_t; #include #ifdef __KERNEL__ -struct old_sigaction { - __sighandler_t sa_handler; - old_sigset_t sa_mask; - unsigned long sa_flags; - __sigrestore_t sa_restorer; -}; - struct sigaction { __sighandler_t sa_handler; unsigned long sa_flags; -- cgit v0.10.2 From 9a07880222b6e50cee2c2d66270cff0c34bfe7b8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 16:21:28 -0400 Subject: avr32: struct old_sigaction is never used Signed-off-by: Al Viro diff --git a/arch/avr32/include/asm/signal.h b/arch/avr32/include/asm/signal.h index 8790dfc..ae56849 100644 --- a/arch/avr32/include/asm/signal.h +++ b/arch/avr32/include/asm/signal.h @@ -115,13 +115,6 @@ typedef unsigned long sigset_t; #include #ifdef __KERNEL__ -struct old_sigaction { - __sighandler_t sa_handler; - old_sigset_t sa_mask; - unsigned long sa_flags; - __sigrestore_t sa_restorer; -}; - struct sigaction { __sighandler_t sa_handler; unsigned long sa_flags; -- cgit v0.10.2 From 187cd44e147ec7245ddd97bbd3305d29583288a9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 16:51:36 -0400 Subject: sparc: missing checks of __get_user()/__put_user() return values Signed-off-by: Al Viro diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 948700f..bb1513e 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -215,8 +215,9 @@ void do_sigreturn32(struct pt_regs *regs) (((unsigned long) sf) & 3)) goto segv; - get_user(pc, &sf->info.si_regs.pc); - __get_user(npc, &sf->info.si_regs.npc); + if (get_user(pc, &sf->info.si_regs.pc) || + __get_user(npc, &sf->info.si_regs.npc)) + goto segv; if ((pc | npc) & 3) goto segv; @@ -305,8 +306,9 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) (((unsigned long) sf) & 3)) goto segv; - get_user(pc, &sf->regs.pc); - __get_user(npc, &sf->regs.npc); + if (get_user(pc, &sf->regs.pc) || + __get_user(npc, &sf->regs.npc)) + goto segv; if ((pc | npc) & 3) goto segv; diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index 627e89a..cd99c1a 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c @@ -184,10 +184,10 @@ sparc_sigaction (int sig, const struct old_sigaction __user *act, if (!access_ok(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || + __get_user(new_ka.sa.sa_flags, &act->sa_flags) || + __get_user(mask, &act->sa_mask)) return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); new_ka.ka_restorer = NULL; } @@ -202,10 +202,10 @@ sparc_sigaction (int sig, const struct old_sigaction __user *act, */ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || + __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret; -- cgit v0.10.2 From a46808e1b75216f175a12cd16e3af3be2d4a53d4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 16:59:56 -0400 Subject: sh: missing checks of __get_user()/__put_user() return values Signed-off-by: Al Viro diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 04d776f..cb4172c 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c @@ -71,10 +71,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, old_sigset_t mask; if (!access_ok(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || + __get_user(new_ka.sa.sa_flags, &act->sa_flags) || + __get_user(mask, &act->sa_mask)) return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); } @@ -83,10 +83,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, if (!ret && oact) { if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || + __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret; @@ -150,12 +150,11 @@ static inline int save_sigcontext_fpu(struct sigcontext __user *sc, if (!(boot_cpu_data.flags & CPU_HAS_FPU)) return 0; - if (!used_math()) { - __put_user(0, &sc->sc_ownedfp); - return 0; - } + if (!used_math()) + return __put_user(0, &sc->sc_ownedfp); - __put_user(1, &sc->sc_ownedfp); + if (__put_user(1, &sc->sc_ownedfp)) + return -EFAULT; /* This will cause a "finit" to be triggered by the next attempted FPU operation by the 'current' process. @@ -195,7 +194,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p regs->sr |= SR_FD; /* Release FPU */ clear_fpu(tsk, regs); clear_used_math(); - __get_user (owned_fp, &sc->sc_ownedfp); + err |= __get_user (owned_fp, &sc->sc_ownedfp); if (owned_fp) err |= restore_sigcontext_fpu(sc); } @@ -386,11 +385,14 @@ static int setup_frame(int sig, struct k_sigaction *ka, struct fdpic_func_descriptor __user *funcptr = (struct fdpic_func_descriptor __user *)ka->sa.sa_handler; - __get_user(regs->pc, &funcptr->text); - __get_user(regs->regs[12], &funcptr->GOT); + err |= __get_user(regs->pc, &funcptr->text); + err |= __get_user(regs->regs[12], &funcptr->GOT); } else regs->pc = (unsigned long)ka->sa.sa_handler; + if (err) + goto give_sigsegv; + set_fs(USER_DS); pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", @@ -470,11 +472,14 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, struct fdpic_func_descriptor __user *funcptr = (struct fdpic_func_descriptor __user *)ka->sa.sa_handler; - __get_user(regs->pc, &funcptr->text); - __get_user(regs->regs[12], &funcptr->GOT); + err |= __get_user(regs->pc, &funcptr->text); + err |= __get_user(regs->regs[12], &funcptr->GOT); } else regs->pc = (unsigned long)ka->sa.sa_handler; + if (err) + goto give_sigsegv; + set_fs(USER_DS); pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index 8f6ed23..b589a35 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c @@ -173,10 +173,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, old_sigset_t mask; if (!access_ok(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || + __get_user(new_ka.sa.sa_flags, &act->sa_flags) || + __get_user(mask, &act->sa_mask)) return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); } @@ -185,10 +185,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, if (!ret && oact) { if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || + __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret; -- cgit v0.10.2 From 43f16819d54e12c025cf8400b8572017e631d948 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 17:01:49 -0400 Subject: powerpc: missing checks of __get_user()/__put_user() return values Signed-off-by: Al Viro diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index ac1f960..61f6aff 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -204,10 +204,10 @@ static inline int get_old_sigaction(struct k_sigaction *new_ka, if (!access_ok(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka->sa.sa_handler, &act->sa_handler) || - __get_user(new_ka->sa.sa_restorer, &act->sa_restorer)) + __get_user(new_ka->sa.sa_restorer, &act->sa_restorer) || + __get_user(new_ka->sa.sa_flags, &act->sa_flags) || + __get_user(mask, &act->sa_mask)) return -EFAULT; - __get_user(new_ka->sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); siginitset(&new_ka->sa.sa_mask, mask); return 0; } -- cgit v0.10.2 From 24d696a776e27268a52cb4ff1060337f409d5789 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 17:18:10 -0400 Subject: cris: missing checks of __get_user()/__put_user() return values Signed-off-by: Al Viro diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c index df40fa8..e16f8f2 100644 --- a/arch/cris/arch-v10/kernel/signal.c +++ b/arch/cris/arch-v10/kernel/signal.c @@ -65,10 +65,10 @@ int sys_sigaction(int sig, const struct old_sigaction __user *act, old_sigset_t mask; if (!access_ok(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || + __get_user(new_ka.sa.sa_flags, &act->sa_flags) || + __get_user(mask, &act->sa_mask)) return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); } @@ -77,10 +77,10 @@ int sys_sigaction(int sig, const struct old_sigaction __user *act, if (!ret && oact) { if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || + __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret; diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index a45efc7..b338d8f 100644 --- a/arch/cris/arch-v32/kernel/signal.c +++ b/arch/cris/arch-v32/kernel/signal.c @@ -79,11 +79,11 @@ sys_sigaction(int signal, const struct old_sigaction *act, if (!access_ok(VERIFY_READ, act, sizeof(*act)) || __get_user(newk.sa.sa_handler, &act->sa_handler) || - __get_user(newk.sa.sa_restorer, &act->sa_restorer)) + __get_user(newk.sa.sa_restorer, &act->sa_restorer) || + __get_user(newk.sa.sa_flags, &act->sa_flags) || + __get_user(mask, &act->sa_mask)) return -EFAULT; - __get_user(newk.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); siginitset(&newk.sa.sa_mask, mask); } @@ -92,11 +92,11 @@ sys_sigaction(int signal, const struct old_sigaction *act, if (!retval && oact) { if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(oldk.sa.sa_handler, &oact->sa_handler) || - __put_user(oldk.sa.sa_restorer, &oact->sa_restorer)) + __put_user(oldk.sa.sa_restorer, &oact->sa_restorer) || + __put_user(oldk.sa.sa_flags, &oact->sa_flags) || + __put_user(oldk.sa.sa_mask.sig[0], &oact->sa_mask)) return -EFAULT; - __put_user(oldk.sa.sa_flags, &oact->sa_flags); - __put_user(oldk.sa.sa_mask.sig[0], &oact->sa_mask); } return retval; -- cgit v0.10.2 From f0c22cddb3046d0addef410c2769688c9ecef498 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 17:20:02 -0400 Subject: frv: missing checks of __get_user()/__put_user() return values Signed-off-by: Al Viro diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index b46a820..8cf5dca 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -56,10 +56,10 @@ asmlinkage int sys_sigaction(int sig, old_sigset_t mask; if (!access_ok(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || + __get_user(new_ka.sa.sa_flags, &act->sa_flags) || + __get_user(mask, &act->sa_mask)) return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); } @@ -68,10 +68,10 @@ asmlinkage int sys_sigaction(int sig, if (!ret && oact) { if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || + __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret; -- cgit v0.10.2 From 79afd8efdb4895747f98b1b9f7712489ce57d46c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 17:21:18 -0400 Subject: h8300: missing checks of __get_user()/__put_user() return values Signed-off-by: Al Viro diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index b5e360a..d4b0555 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c @@ -71,10 +71,10 @@ sys_sigaction(int sig, const struct old_sigaction *act, old_sigset_t mask; if (!access_ok(VERIFY_READ, act, sizeof(*act)) || __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || + __get_user(new_ka.sa.sa_flags, &act->sa_flags) || + __get_user(mask, &act->sa_mask)) return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); } @@ -83,10 +83,10 @@ sys_sigaction(int sig, const struct old_sigaction *act, if (!ret && oact) { if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || + __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); } return ret; -- cgit v0.10.2 From 899dfaa7e7dd825f8366c2a6b38067db43644dc6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 17:28:06 -0400 Subject: sparc: kill ancient comment in sparc_sigaction() It used to be true, until 2.1.78 (14 years ago) when we switched to do_sigaction()... Signed-off-by: Al Viro diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index cd99c1a..0c9b31b 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c @@ -195,11 +195,6 @@ sparc_sigaction (int sig, const struct old_sigaction __user *act, ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); if (!ret && oact) { - /* In the clone() case we could copy half consistent - * state to the user, however this could sleep and - * deadlock us if we held the signal lock on SMP. So for - * now I take the easy way out and do no locking. - */ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || -- cgit v0.10.2 From a54f1655be4cb103a6729adcc9ca914c5fdf1ca0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 24 Apr 2012 01:46:23 -0400 Subject: m68k: add TIF_NOTIFY_RESUME and handle it. TIF_NOTIFY_RESUME added (as bit 5). That way nommu glue needs no changes at all; mmu one needs just to replace jmi do_signal_return to jne do_signal_return There we have flags shifted up, until bit 6 (SIGPENDING) is in MSBit; instead of checking that MSBit is set (jmi) we check that MSBit or something below it is set (jne); bits 0..4 are never set, so that's precisely "bit 6 or bit 5 is set". Usual handling of NOTIFY_RESUME/SIGPENDING is done in do_notify_resume(); glue calls it instead of do_signal(). Signed-off-by: Al Viro diff --git a/arch/m68k/include/asm/thread_info.h b/arch/m68k/include/asm/thread_info.h index e8665e6..126131f 100644 --- a/arch/m68k/include/asm/thread_info.h +++ b/arch/m68k/include/asm/thread_info.h @@ -71,6 +71,7 @@ static inline struct thread_info *current_thread_info(void) * bits 0-7 are tested at every exception exit * bits 8-15 are also tested at syscall exit */ +#define TIF_NOTIFY_RESUME 5 /* callback before returning to user */ #define TIF_SIGPENDING 6 /* signal pending */ #define TIF_NEED_RESCHED 7 /* rescheduling necessary */ #define TIF_DELAYED_TRACE 14 /* single step a syscall */ diff --git a/arch/m68k/kernel/entry_mm.S b/arch/m68k/kernel/entry_mm.S index 675a854..f29e73c 100644 --- a/arch/m68k/kernel/entry_mm.S +++ b/arch/m68k/kernel/entry_mm.S @@ -148,7 +148,7 @@ syscall_exit_work: jcs do_trace_exit jmi do_delayed_trace lslw #8,%d0 - jmi do_signal_return + jne do_signal_return pea resume_userspace jra schedule @@ -172,7 +172,7 @@ exit_work: | save top of frame movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) lslb #1,%d0 - jmi do_signal_return + jne do_signal_return pea resume_userspace jra schedule @@ -182,7 +182,7 @@ do_signal_return: subql #4,%sp | dummy return address SAVE_SWITCH_STACK pea %sp@(SWITCH_STACK_SIZE) - bsrl do_signal + bsrl do_notify_resume addql #4,%sp RESTORE_SWITCH_STACK addql #4,%sp diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index d8f6960..d9f3d19 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -1154,7 +1155,7 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -asmlinkage void do_signal(struct pt_regs *regs) +static void do_signal(struct pt_regs *regs) { siginfo_t info; struct k_sigaction ka; @@ -1186,3 +1187,15 @@ asmlinkage void do_signal(struct pt_regs *regs) sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); } } + +void do_notify_resume(struct pt_regs *regs) +{ + if (test_thread_flag(TIF_SIGPENDING)) + do_signal(regs); + + if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) { + tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); + } +} diff --git a/arch/m68k/platform/68328/entry.S b/arch/m68k/platform/68328/entry.S index 5c39b80..7f91c2f 100644 --- a/arch/m68k/platform/68328/entry.S +++ b/arch/m68k/platform/68328/entry.S @@ -119,7 +119,7 @@ Lsignal_return: subql #4,%sp /* dummy return address*/ SAVE_SWITCH_STACK pea %sp@(SWITCH_STACK_SIZE) - bsrw do_signal + bsrw do_notify_resume addql #4,%sp RESTORE_SWITCH_STACK addql #4,%sp diff --git a/arch/m68k/platform/68360/entry.S b/arch/m68k/platform/68360/entry.S index aa47d1d..904fd9a 100644 --- a/arch/m68k/platform/68360/entry.S +++ b/arch/m68k/platform/68360/entry.S @@ -115,7 +115,7 @@ Lsignal_return: subql #4,%sp /* dummy return address*/ SAVE_SWITCH_STACK pea %sp@(SWITCH_STACK_SIZE) - bsrw do_signal + bsrw do_notify_resume addql #4,%sp RESTORE_SWITCH_STACK addql #4,%sp diff --git a/arch/m68k/platform/coldfire/entry.S b/arch/m68k/platform/coldfire/entry.S index 281e38c..881ab8e 100644 --- a/arch/m68k/platform/coldfire/entry.S +++ b/arch/m68k/platform/coldfire/entry.S @@ -152,7 +152,7 @@ Lsignal_return: subql #4,%sp /* dummy return address */ SAVE_SWITCH_STACK pea %sp@(SWITCH_STACK_SIZE) - jsr do_signal + jsr do_notify_resume addql #4,%sp RESTORE_SWITCH_STACK addql #4,%sp -- cgit v0.10.2 From 1d5d4dbe810befe63e79b2d6cdcad2066e3b1fc4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 24 Apr 2012 01:55:30 -0400 Subject: score: add handling of NOTIFY_RESUME to do_notify_resume() It's already called if TIF_NOTIFY_RESUME is set, so we only need to add the actual work. Note that checking for RESTORE_SIGMASK was not needed - set_restore_sigmask() also sets SIGPENDING, so we never RESTORE_SIGMASK without SIGPENDING. Signed-off-by: Al Viro diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c index a087ad8..d4a49011 100644 --- a/arch/score/kernel/signal.c +++ b/arch/score/kernel/signal.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -350,6 +351,12 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) { /* deal with pending signal delivery */ - if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) + if (thread_info_flags & _TIF_SIGPENDING) do_signal(regs); + if (thread_info_flags & _TIF_NOTIFY_RESUME) { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); + } } -- cgit v0.10.2 From 969a96168091f837645a674a9f7ed1a9aaa1424b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 24 Apr 2012 02:03:06 -0400 Subject: microblaze: handle TIF_NOTIFY_RESUME Signed-off-by: Al Viro diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S index f104d27..ea2dd42 100644 --- a/arch/microblaze/kernel/entry-nommu.S +++ b/arch/microblaze/kernel/entry-nommu.S @@ -132,11 +132,11 @@ ret_from_intr: beqi r11, 1f bralid r15, schedule nop -1: andi r11, r19, _TIF_SIGPENDING +1: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME beqid r11, no_intr_resched addk r5, r1, r0 addk r7, r0, r0 - bralid r15, do_signal + bralid r15, do_notify_resume addk r6, r0, r0 no_intr_resched: @@ -292,8 +292,8 @@ ENTRY(_user_exception) /* * Debug traps are like a system call, but entered via brki r14, 0x60 - * All we need to do is send the SIGTRAP signal to current, ptrace and do_signal - * will handle the rest + * All we need to do is send the SIGTRAP signal to current, ptrace and + * do_notify_resume will handle the rest */ ENTRY(_debug_exception) swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */ @@ -482,11 +482,11 @@ work_pending: beqi r11, 1f bralid r15, schedule nop -1: andi r11, r19, _TIF_SIGPENDING +1: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME beqi r11, no_work_pending addk r5, r1, r0 addik r7, r0, 1 - bralid r15, do_signal + bralid r15, do_notify_resume addk r6, r0, r0 bri no_work_pending diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 66e34a3..3cee913 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -430,12 +430,12 @@ C_ENTRY(ret_from_trap): 5: /* get thread info from current task*/ lwi r11, CURRENT_TASK, TS_THREAD_INFO; lwi r11, r11, TI_FLAGS; /* get flags in thread info */ - andi r11, r11, _TIF_SIGPENDING; + andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; beqi r11, 1f; /* Signals to handle, handle them */ addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ addi r7, r0, 1; /* Arg 3: int in_syscall */ - bralid r15, do_signal; /* Handle any signals */ + bralid r15, do_notify_resume; /* Handle any signals */ add r6, r0, r0; /* Arg 2: sigset_t *oldset */ /* Finally, return to user state. */ @@ -622,7 +622,7 @@ C_ENTRY(ret_from_exc): /* Maybe handle a signal */ 5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ lwi r11, r11, TI_FLAGS; /* get flags in thread info */ - andi r11, r11, _TIF_SIGPENDING; + andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; beqi r11, 1f; /* Signals to handle, handle them */ /* @@ -635,10 +635,10 @@ C_ENTRY(ret_from_exc): * traps), but signal handlers may want to examine or change the * complete register state. Here we save anything not saved by * the normal entry sequence, so that it may be safely restored - * (in a possibly modified form) after do_signal returns. */ + * (in a possibly modified form) after do_notify_resume returns. */ addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ addi r7, r0, 0; /* Arg 3: int in_syscall */ - bralid r15, do_signal; /* Handle any signals */ + bralid r15, do_notify_resume; /* Handle any signals */ add r6, r0, r0; /* Arg 2: sigset_t *oldset */ /* Finally, return to user state. */ @@ -732,12 +732,12 @@ ret_from_irq: /* Maybe handle a signal */ 5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* MS: get thread info */ lwi r11, r11, TI_FLAGS; /* get flags in thread info */ - andi r11, r11, _TIF_SIGPENDING; + andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; beqid r11, no_intr_resched /* Handle a signal return; Pending signals should be in r18. */ addi r7, r0, 0; /* Arg 3: int in_syscall */ addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ - bralid r15, do_signal; /* Handle any signals */ + bralid r15, do_notify_resume; /* Handle any signals */ add r6, r0, r0; /* Arg 2: sigset_t *oldset */ /* Finally, return to user state. */ @@ -869,12 +869,12 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */ /* Maybe handle a signal */ 5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ lwi r11, r11, TI_FLAGS; /* get flags in thread info */ - andi r11, r11, _TIF_SIGPENDING; + andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; beqi r11, 1f; /* Signals to handle, handle them */ addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ addi r7, r0, 0; /* Arg 3: int in_syscall */ - bralid r15, do_signal; /* Handle any signals */ + bralid r15, do_notify_resume; /* Handle any signals */ add r6, r0, r0; /* Arg 2: sigset_t *oldset */ /* Finally, return to user state. */ diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index fbdb026..449886d 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -42,8 +43,6 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall); - asmlinkage long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, struct pt_regs *regs) @@ -340,7 +339,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall) +static int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall) { siginfo_t info; int signr; @@ -350,14 +349,6 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall) printk(KERN_INFO "do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1, regs->r12, current_thread_info()->flags); #endif - /* - * We want the common case to go fast, which - * is why we may in certain cases get here from - * kernel mode. Just return without doing anything - * if so. - */ - if (kernel_mode(regs)) - return 1; if (current_thread_info()->status & TS_RESTORE_SIGMASK) oldset = ¤t->saved_sigmask; @@ -397,3 +388,24 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall) /* Did we come from a system call? */ return 0; } + +void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, int in_syscall) +{ + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if (kernel_mode(regs)) + return; + + if (test_thread_flag(TIF_SIGPENDING)) + do_signal(regs, oldset, in_syscall); + + if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) { + tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); + } +} -- cgit v0.10.2 From 8314019141e4f7274ea4dc264a47bbb2e17c66dd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 24 Apr 2012 02:21:18 -0400 Subject: microblaze: drop 'oldset' argument of do_notify_resume() never used... Signed-off-by: Al Viro diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S index ea2dd42..75c3ea1 100644 --- a/arch/microblaze/kernel/entry-nommu.S +++ b/arch/microblaze/kernel/entry-nommu.S @@ -135,7 +135,6 @@ ret_from_intr: 1: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME beqid r11, no_intr_resched addk r5, r1, r0 - addk r7, r0, r0 bralid r15, do_notify_resume addk r6, r0, r0 @@ -485,9 +484,8 @@ work_pending: 1: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME beqi r11, no_work_pending addk r5, r1, r0 - addik r7, r0, 1 bralid r15, do_notify_resume - addk r6, r0, r0 + addik r6, r0, 1 bri no_work_pending ENTRY(ret_to_user) diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 3cee913..daff9e5 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -434,9 +434,8 @@ C_ENTRY(ret_from_trap): beqi r11, 1f; /* Signals to handle, handle them */ addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ - addi r7, r0, 1; /* Arg 3: int in_syscall */ bralid r15, do_notify_resume; /* Handle any signals */ - add r6, r0, r0; /* Arg 2: sigset_t *oldset */ + addi r6, r0, 1; /* Arg 2: int in_syscall */ /* Finally, return to user state. */ 1: set_bip; /* Ints masked for state restore */ @@ -637,9 +636,8 @@ C_ENTRY(ret_from_exc): * the normal entry sequence, so that it may be safely restored * (in a possibly modified form) after do_notify_resume returns. */ addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ - addi r7, r0, 0; /* Arg 3: int in_syscall */ bralid r15, do_notify_resume; /* Handle any signals */ - add r6, r0, r0; /* Arg 2: sigset_t *oldset */ + addi r6, r0, 0; /* Arg 2: int in_syscall */ /* Finally, return to user state. */ 1: set_bip; /* Ints masked for state restore */ @@ -735,10 +733,9 @@ ret_from_irq: andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME; beqid r11, no_intr_resched /* Handle a signal return; Pending signals should be in r18. */ - addi r7, r0, 0; /* Arg 3: int in_syscall */ addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ bralid r15, do_notify_resume; /* Handle any signals */ - add r6, r0, r0; /* Arg 2: sigset_t *oldset */ + addi r6, r0, 0; /* Arg 2: int in_syscall */ /* Finally, return to user state. */ no_intr_resched: @@ -873,9 +870,8 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */ beqi r11, 1f; /* Signals to handle, handle them */ addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */ - addi r7, r0, 0; /* Arg 3: int in_syscall */ bralid r15, do_notify_resume; /* Handle any signals */ - add r6, r0, r0; /* Arg 2: sigset_t *oldset */ + addi r6, r0, 0; /* Arg 2: int in_syscall */ /* Finally, return to user state. */ 1: swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 449886d..7f4c7be 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c @@ -339,13 +339,14 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -static int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall) +static void do_signal(struct pt_regs *regs, int in_syscall) { siginfo_t info; int signr; struct k_sigaction ka; + sigset_t *oldset; #ifdef DEBUG_SIG - printk(KERN_INFO "do signal: %p %p %d\n", regs, oldset, in_syscall); + printk(KERN_INFO "do signal: %p %d\n", regs, in_syscall); printk(KERN_INFO "do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1, regs->r12, current_thread_info()->flags); #endif @@ -370,7 +371,7 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall) current_thread_info()->status &= ~TS_RESTORE_SIGMASK; } - return 1; + return; } if (in_syscall) @@ -384,12 +385,9 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall) current_thread_info()->status &= ~TS_RESTORE_SIGMASK; sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); } - - /* Did we come from a system call? */ - return 0; } -void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, int in_syscall) +void do_notify_resume(struct pt_regs *regs, int in_syscall) { /* * We want the common case to go fast, which @@ -401,7 +399,7 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, int in_syscall) return; if (test_thread_flag(TIF_SIGPENDING)) - do_signal(regs, oldset, in_syscall); + do_signal(regs, in_syscall); if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) { tracehook_notify_resume(regs); -- cgit v0.10.2 From a53bb24e7666870bbc195e295a936aa0a58ce313 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 24 Apr 2012 02:30:16 -0400 Subject: xtensa: add handling of TIF_NOTIFY_RESUME Signed-off-by: Al Viro diff --git a/arch/xtensa/include/asm/thread_info.h b/arch/xtensa/include/asm/thread_info.h index 6abbedd..81abfd5 100644 --- a/arch/xtensa/include/asm/thread_info.h +++ b/arch/xtensa/include/asm/thread_info.h @@ -131,6 +131,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_IRET 4 /* return with iret */ #define TIF_MEMDIE 5 /* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 6 /* restore signal mask in do_signal() */ +#define TIF_NOTIFY_RESUME 7 /* callback before returning to user */ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define _TIF_SYSCALL_TRACE (1< #include #include +#include #include #include @@ -446,16 +447,13 @@ asmlinkage long xtensa_sigaltstack(const stack_t __user *uss, * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -void do_signal(struct pt_regs *regs) +static void do_signal(struct pt_regs *regs) { siginfo_t info; int signr; struct k_sigaction ka; sigset_t oldset; - if (!user_mode(regs)) - return; - if (try_to_freeze()) goto no_signal; @@ -542,3 +540,17 @@ no_signal: return; } +void do_notify_resume(struct pt_regs *regs) +{ + if (!user_mode(regs)) + return; + + if (test_thread_flag(TIF_SIGPENDING)) + do_signal(regs); + + if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) { + tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); + } +} -- cgit v0.10.2 From 415d04d08fec74b226c92c1fb54ad117c9c6bac4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 26 Apr 2012 18:17:28 -0400 Subject: unicore32: if there's no handler we need to restore sigmask, syscall or no syscall Signed-off-by: Al Viro diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c index 72d9531..7754df6 100644 --- a/arch/unicore32/kernel/signal.c +++ b/arch/unicore32/kernel/signal.c @@ -447,15 +447,12 @@ static void do_signal(struct pt_regs *regs, int syscall) regs->UCreg_00 == -ERESTARTNOINTR) { setup_syscall_restart(regs); } - - /* If there's no signal to deliver, we just put the saved - * sigmask back. - */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) { - clear_thread_flag(TIF_RESTORE_SIGMASK); - sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); - } } + /* If there's no signal to deliver, we just put the saved + * sigmask back. + */ + if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK)) + set_current_blocked(¤t->saved_sigmask); } asmlinkage void do_notify_resume(struct pt_regs *regs, -- cgit v0.10.2