From 68f3f16d9ad0f1e28ab3fd0001ab5798c41f15a3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 21 May 2012 21:42:32 -0400 Subject: [PATCH 01/55] 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 --- arch/alpha/kernel/signal.c | 11 +---------- arch/arm/kernel/signal.c | 11 +---------- arch/cris/arch-v10/kernel/signal.c | 16 ++++------------ arch/cris/arch-v32/kernel/signal.c | 16 ++++------------ arch/frv/kernel/signal.c | 14 +++----------- arch/m68k/kernel/signal.c | 15 +++------------ arch/mips/kernel/signal.c | 20 ++------------------ arch/mips/kernel/signal32.c | 20 ++------------------ arch/mips/kernel/signal_n32.c | 10 +--------- arch/mn10300/kernel/signal.c | 14 +++----------- arch/powerpc/kernel/signal_32.c | 11 +---------- arch/s390/kernel/signal.c | 9 +-------- arch/sh/kernel/signal_32.c | 12 +----------- arch/sparc/kernel/signal_32.c | 12 +----------- arch/sparc/kernel/signal_64.c | 13 +------------ arch/um/kernel/signal.c | 9 +-------- arch/x86/ia32/ia32_signal.c | 12 +----------- arch/x86/kernel/signal.c | 12 +----------- include/linux/signal.h | 1 + kernel/compat.c | 10 +--------- kernel/signal.c | 25 ++++++++++++++++--------- 21 files changed, 50 insertions(+), 223 deletions(-) diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 35f2ef44de1262..74b05e6ed44153 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 73d9a420850def..4e5fdd9bd9e397 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 289c584ba49950..170f4970d59051 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 ce4ab1a5552cae..e09083208cb605 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 bab01298b58ee2..df957c7ba38772 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 1747c7030a336e..8186982fb32076 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 d5a338a1739c90..17f6ee30ad0d60 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 ac3b8d89aae51a..b4fe2eacbd5d25 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 86eb4b04631c43..63ffac9af7c5b6 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 690f4e9507d778..50eb94a05826b1 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 45eb998557f8c3..ac1f96027bf56e 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 8a4e2b760d562e..f626232e216c0c 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 5901fba3176e51..46c9f9b00b14d5 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 ac8e66b50f07d8..2b7e849f7c6528 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 48b0f57b65f7e8..eafaab486b2d24 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 fb12f4c5e649f6..b9b75b3bd5c93b 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 a69245ba27e328..fa54410c666652 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 115eac431483cb..b68ccadd2ff4ba 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 7987ce74874b36..17046cc484bced 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 d2c67aa49ae667..c28a306ae05c06 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 17afcaf582d07a..3ad220a81619d8 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 */ From ade7728b4e9aac4cc82117e3e35c5745b7d16037 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:58 +1000 Subject: [PATCH 02/55] 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 --- arch/parisc/kernel/signal.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 12c1ed33dc18b9..bd36152b780e3c 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) || From 7ebe0c5d7205a356532f2321e03d85bfd2443374 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:52 +1000 Subject: [PATCH 03/55] 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 --- arch/frv/kernel/signal.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index df957c7ba38772..b46a8202979b7d 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; From 8e3f9f65cb722d3663032b97ca76377b864f3835 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:11 +1000 Subject: [PATCH 04/55] 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 --- arch/blackfin/kernel/signal.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c index d536f35d1f4394..05ece020f8a309 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; } From 9ae36796020998fcd07431934be6b160e9c7bfce Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:06 +1000 Subject: [PATCH 05/55] 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 --- arch/unicore32/kernel/signal.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c index 911b549a6df54d..72d953190419de 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; } From 97c47bb70728c765d6cbf582759f9170fe152ded Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:06 +1000 Subject: [PATCH 06/55] 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 --- arch/h8300/kernel/signal.c | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index af842c369d2430..cd63f5a6c8fe9d 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); } /* From 80c1dfa91c44665f2cecc1666050b2e8e04cef68 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:05 +1000 Subject: [PATCH 07/55] 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 --- arch/score/kernel/signal.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c index aa57440e49733e..bf9e33e05334e3 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; } From 4c3181bd3bde449d79b04e127b41ef02cade8005 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:05 +1000 Subject: [PATCH 08/55] 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 --- arch/score/kernel/signal.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c index bf9e33e05334e3..5a5bd17633360e 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; } From de8f2ddd69fc817b66138b36d656a2973d6afd8a Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:03 +1000 Subject: [PATCH 09/55] 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 --- arch/microblaze/kernel/signal.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 59967116898000..90de06da3f6fc5 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 */ From a12c3694aeb0321d5e6a50321c63881bd92a1bf2 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:04 +1000 Subject: [PATCH 10/55] 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 --- arch/microblaze/kernel/signal.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 90de06da3f6fc5..9e749c032af808 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, From bcb8c8d0b7131df1b5aad011db33e17f8def5d0b Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:04 +1000 Subject: [PATCH 11/55] 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 --- arch/microblaze/kernel/signal.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 9e749c032af808..f2c13d5a6261b3 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, From 60c597513ee93fc6a0b7f2cb83d0aa67d4204cf1 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:05 +1000 Subject: [PATCH 12/55] 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 --- arch/microblaze/kernel/signal.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index f2c13d5a6261b3..99b970866b29a1 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; } From 7a076e4ff07ffc2c219285ec57aed8bdde86cb37 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:03 +1000 Subject: [PATCH 13/55] 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 --- arch/ia64/kernel/signal.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index 7bdafc8788bd6e..7523501d3bc087 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. From f3b5e822739c70663aee8584b7993afe055431c9 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:58:00 +1000 Subject: [PATCH 14/55] 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 --- arch/cris/arch-v10/kernel/signal.c | 22 +++++----------------- arch/cris/arch-v32/kernel/signal.c | 25 ++++--------------------- 2 files changed, 9 insertions(+), 38 deletions(-) diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c index 170f4970d59051..df40fa80480fdc 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 e09083208cb605..b0a6cf4f2cad47 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; } From 00f35785fae2ae8a37b3a3dc1f2dc05e8f232bef Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:57:59 +1000 Subject: [PATCH 15/55] 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 --- arch/mn10300/kernel/signal.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c index 50eb94a05826b1..890cf91767cc84 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; } From 3883e301bf05457d09ffc16c03ead6182ac3d732 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:57:59 +1000 Subject: [PATCH 16/55] 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 --- arch/m32r/kernel/signal.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index a08697f0886d79..f54d96993ea187 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; } From e1b1fd79a04396d5ec971e9e4d4711b5a58ad7e3 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:57:57 +1000 Subject: [PATCH 17/55] 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 --- arch/avr32/kernel/signal.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 64f886fac2efef..9c075e105d603b 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); } /* From 49209590cb1cdd30b35edd65535184e39bfbab99 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 11 May 2012 10:57:58 +1000 Subject: [PATCH 18/55] 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 --- arch/avr32/kernel/signal.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 9c075e105d603b..06f4293f85d8a9 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); } /* From 54bbf3e3a9af5e3c439766fda444fb0673a1a721 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:57:58 +1000 Subject: [PATCH 19/55] 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 --- arch/avr32/kernel/signal.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 06f4293f85d8a9..feeb77bd81c702 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); } /* From 3334bf12480f10377e44d932baf53f34ec737f8b Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 11 May 2012 10:59:08 +1000 Subject: [PATCH 20/55] 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 --- arch/hexagon/kernel/signal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c index ecbab34576061a..ab5f5ad1271333 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(); } From 43a35995562495bd70a87b5d3a2e820036ee6597 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Fri, 11 May 2012 10:57:59 +1000 Subject: [PATCH 21/55] 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 --- arch/m68k/kernel/signal.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index 8186982fb32076..d8f6960e8fd9ec 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; From 85a847ffad1d4ee94590db25bad444d18a8db263 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 03:15:40 -0400 Subject: [PATCH 22/55] parisc: resetting ->restart_block.fn needs to be done on rt_sigreturn() Signed-off-by: Al Viro --- arch/parisc/kernel/signal.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index bd36152b780e3c..4b9cb0d546d132 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; From 2a3fdc117cdd664814d7374941698729e47fea95 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 03:30:18 -0400 Subject: [PATCH 23/55] c6x: ->restart_block.fn needs to be reset on rt_sigreturn Signed-off-by: Al Viro --- arch/c6x/kernel/signal.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/c6x/kernel/signal.c b/arch/c6x/kernel/signal.c index 3b5a0509998994..cf37478c1169c5 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 From ef9b122f322d9d9550160ca33a6efbd759a43b55 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 03:31:24 -0400 Subject: [PATCH 24/55] hexagon: ->restart_block.fn needs to be reset on rt_sigreturn Signed-off-by: Al Viro --- arch/hexagon/kernel/signal.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c index ab5f5ad1271333..434866eb0f1cf3 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; From 58e4257bc6336db015673a8cb598bd6cdbecf6d1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 03:32:18 -0400 Subject: [PATCH 25/55] microblaze: ->restart_block.fn needs to be reset on rt_sigreturn Signed-off-by: Al Viro --- arch/microblaze/kernel/signal.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 99b970866b29a1..fbdb02641821d7 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; From f2ccfb3e565f51f1063d68f119d5b42a7f5fd984 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 03:33:45 -0400 Subject: [PATCH 26/55] score: ->restart_block.fn needs to be reset on rt_sigreturn Signed-off-by: Al Viro --- arch/score/kernel/signal.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c index 5a5bd17633360e..c3fded7357f0b3 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; From 188f677f84e935f83e3d539d6e8808006f6ac62f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 03:35:28 -0400 Subject: [PATCH 27/55] xtensa: ->restart_block.fn needs to be reset on rt_sigreturn Signed-off-by: Al Viro --- arch/xtensa/kernel/signal.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index d78869a00b11c8..44e9329a64840e 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"); From 446cdd13275bfa38b858a1e99dbd61c07c9767c0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 03:36:05 -0400 Subject: [PATCH 28/55] avr32: ->restart_block.fn needs to be reset on rt_sigreturn Signed-off-by: Al Viro --- arch/avr32/kernel/signal.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index feeb77bd81c702..a4855aecbe444b 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); From 9ccc9c75c9117d18a9b1f71a21f0066b1eb9db6f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 00:59:07 -0400 Subject: [PATCH 29/55] xtensa: switch to generic rt_sigsuspend(2) Signed-off-by: Al Viro --- arch/xtensa/include/asm/syscall.h | 2 -- arch/xtensa/include/asm/unistd.h | 2 +- arch/xtensa/kernel/entry.S | 1 - arch/xtensa/kernel/signal.c | 54 +++++++++---------------------- 4 files changed, 16 insertions(+), 43 deletions(-) diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h index efcf33b92e4c02..fc289f7e8ebc7c 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 798ee6d285a10d..bc7e005faa602f 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 6223f3346b5c10..b1bb6d79d8b945 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 44e9329a64840e..bb00cc470ca936 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 @@ static int setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 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 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) 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; } From 9ef461adf9875a0fcaafe4d152a7557740fa1a25 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 01:16:34 -0400 Subject: [PATCH 30/55] 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 --- arch/sh/include/asm/syscalls_32.h | 4 +- arch/sh/include/asm/unistd.h | 4 +- arch/sh/kernel/signal_32.c | 4 +- arch/sh/kernel/signal_64.c | 72 +++++-------------------------- 4 files changed, 13 insertions(+), 71 deletions(-) diff --git a/arch/sh/include/asm/syscalls_32.h b/arch/sh/include/asm/syscalls_32.h index ae717e3c26d6d4..6c1fa559753c10 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 a42a5610a36aa9..e800a38c9f8d86 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 46c9f9b00b14d5..04d776f35869b5 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 3c9a6f7dcdce81..8f6ed236c93201 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); From 8b6c3309c94b7296614d7783eb259555a6be6f7e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 21 Apr 2012 22:42:11 -0400 Subject: [PATCH 31/55] h8300: don't change blocked signals' mask if setting frame up fails Signed-off-by: Al Viro --- arch/h8300/kernel/signal.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index cd63f5a6c8fe9d..78e9b65df93e47 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); } /* From 7ae4e32a65148353db3458e3eb87117f25620ac5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 01:30:05 -0400 Subject: [PATCH 32/55] h8300: switch to saved_sigmask-based sigsuspend/rt_sigsuspend Signed-off-by: Al Viro --- arch/h8300/include/asm/unistd.h | 1 + arch/h8300/kernel/signal.c | 73 +++++++++------------------------ arch/h8300/kernel/syscalls.S | 6 --- 3 files changed, 21 insertions(+), 59 deletions(-) diff --git a/arch/h8300/include/asm/unistd.h b/arch/h8300/include/asm/unistd.h index 2c3f8e60b1e092..718511303b4e15 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 78e9b65df93e47..b5e360a9551963 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 4be2ea2fbe26a4..9d77e715a2edcf 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 From a4e075c43e7fd9af769b28b7cb454615f61e2698 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 May 2012 09:46:55 -0400 Subject: [PATCH 33/55] 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 --- arch/cris/arch-v32/kernel/signal.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index b0a6cf4f2cad47..55905782a41bf8 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); From ae28b38ca14122b990a83bf4ef95a12889cc6b92 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 00:28:50 -0400 Subject: [PATCH 34/55] 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 --- arch/microblaze/kernel/entry-nommu.S | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S index 34b526f59b4378..f104d276b80641 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 From fe49c1cebf054d5c797ecd6b91d5bf96d4295fe4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 2 May 2012 09:52:37 -0400 Subject: [PATCH 35/55] avr32: need to clear RESTORE_SIGMASK on successful signal delivery Signed-off-by: Al Viro --- arch/avr32/kernel/signal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index a4855aecbe444b..ae386c304beefe 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); } /* From 5d71c55bdb020561a9d44c8453ca2a3ca524ea35 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 21 Apr 2012 21:32:46 -0400 Subject: [PATCH 36/55] 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 --- arch/blackfin/kernel/signal.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c index 05ece020f8a309..e5bbc1a5edc242 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; } From 6eef019002e61abdc5e4384e4154d73c9f56d2bc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 21 Apr 2012 21:35:56 -0400 Subject: [PATCH 37/55] cris: don't open-code force_sigsegv() Signed-off-by: Al Viro --- arch/cris/arch-v32/kernel/signal.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index 55905782a41bf8..a45efc7df748aa 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; } From cf4a0ce45c06f79f800f6d8747618901e3a6a8ad Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 21 Apr 2012 21:39:54 -0400 Subject: [PATCH 38/55] score: don't open-code force_sigsegv() Signed-off-by: Al Viro --- arch/score/kernel/signal.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c index c3fded7357f0b3..a087ad85175a30 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; } From cbdfb9ff551cbe3e002387e7fb0256f384c26e91 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 02:34:42 -0400 Subject: [PATCH 39/55] 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 --- arch/alpha/kernel/signal.c | 69 ++++++++++++++------------------------ 1 file changed, 26 insertions(+), 43 deletions(-) diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 74b05e6ed44153..10ab2d74ecbbed 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) { From b1175ed2234235276f4a2256f72a277b85320cf9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 16:19:57 -0400 Subject: [PATCH 40/55] xtensa: xtensa_sigaction doesn't exist ... and struct old_sigaction never used Signed-off-by: Al Viro --- arch/xtensa/include/asm/signal.h | 7 ------- arch/xtensa/include/asm/syscall.h | 2 -- 2 files changed, 9 deletions(-) diff --git a/arch/xtensa/include/asm/signal.h b/arch/xtensa/include/asm/signal.h index 633ba73bc4d21e..7f201b9d419574 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 fc289f7e8ebc7c..0b9f2e13c78128 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 *, From fe2eff8b87a3b33efd1bb30bb775cef71eaca34d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 16:20:52 -0400 Subject: [PATCH 41/55] m32r: struct old_sigaction is never used Signed-off-by: Al Viro --- arch/m32r/include/asm/signal.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/m32r/include/asm/signal.h b/arch/m32r/include/asm/signal.h index b2eeb0de1c8d33..ea5f95e4079eac 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; From 9a07880222b6e50cee2c2d66270cff0c34bfe7b8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 16:21:28 -0400 Subject: [PATCH 42/55] avr32: struct old_sigaction is never used Signed-off-by: Al Viro --- arch/avr32/include/asm/signal.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/avr32/include/asm/signal.h b/arch/avr32/include/asm/signal.h index 8790dfc10d5ba2..ae56849fdb2b94 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; From 187cd44e147ec7245ddd97bbd3305d29583288a9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 16:51:36 -0400 Subject: [PATCH 43/55] sparc: missing checks of __get_user()/__put_user() return values Signed-off-by: Al Viro --- arch/sparc/kernel/signal32.c | 10 ++++++---- arch/sparc/kernel/sys_sparc_32.c | 12 ++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 948700fb90365d..bb1513e45f1a81 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 627e89af1d7128..cd99c1a7870f4d 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; From a46808e1b75216f175a12cd16e3af3be2d4a53d4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 16:59:56 -0400 Subject: [PATCH 44/55] sh: missing checks of __get_user()/__put_user() return values Signed-off-by: Al Viro --- arch/sh/kernel/signal_32.c | 37 +++++++++++++++++++++---------------- arch/sh/kernel/signal_64.c | 12 ++++++------ 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 04d776f35869b5..cb4172c8af7d81 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 8f6ed236c93201..b589a354c069ae 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; From 43f16819d54e12c025cf8400b8572017e631d948 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 17:01:49 -0400 Subject: [PATCH 45/55] powerpc: missing checks of __get_user()/__put_user() return values Signed-off-by: Al Viro --- arch/powerpc/kernel/signal_32.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index ac1f96027bf56e..61f6aff25edc3f 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; } From 24d696a776e27268a52cb4ff1060337f409d5789 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 17:18:10 -0400 Subject: [PATCH 46/55] cris: missing checks of __get_user()/__put_user() return values Signed-off-by: Al Viro --- arch/cris/arch-v10/kernel/signal.c | 12 ++++++------ arch/cris/arch-v32/kernel/signal.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c index df40fa80480fdc..e16f8f297f61a0 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 a45efc7df748aa..b338d8fc0c1241 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; From f0c22cddb3046d0addef410c2769688c9ecef498 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 17:20:02 -0400 Subject: [PATCH 47/55] frv: missing checks of __get_user()/__put_user() return values Signed-off-by: Al Viro --- arch/frv/kernel/signal.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index b46a8202979b7d..8cf5dca01758f7 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; From 79afd8efdb4895747f98b1b9f7712489ce57d46c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 17:21:18 -0400 Subject: [PATCH 48/55] h8300: missing checks of __get_user()/__put_user() return values Signed-off-by: Al Viro --- arch/h8300/kernel/signal.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index b5e360a9551963..d4b0555d290478 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; From 899dfaa7e7dd825f8366c2a6b38067db43644dc6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 22 Apr 2012 17:28:06 -0400 Subject: [PATCH 49/55] 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 --- arch/sparc/kernel/sys_sparc_32.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index cd99c1a7870f4d..0c9b31b22e07e3 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) || From a54f1655be4cb103a6729adcc9ca914c5fdf1ca0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 24 Apr 2012 01:46:23 -0400 Subject: [PATCH 50/55] 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 --- arch/m68k/include/asm/thread_info.h | 1 + arch/m68k/kernel/entry_mm.S | 6 +++--- arch/m68k/kernel/signal.c | 15 ++++++++++++++- arch/m68k/platform/68328/entry.S | 2 +- arch/m68k/platform/68360/entry.S | 2 +- arch/m68k/platform/coldfire/entry.S | 2 +- 6 files changed, 21 insertions(+), 7 deletions(-) diff --git a/arch/m68k/include/asm/thread_info.h b/arch/m68k/include/asm/thread_info.h index e8665e6f9464d2..126131f94a2ca9 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 675a854966a62d..f29e73ca9dbbb7 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 d8f6960e8fd9ec..d9f3d1900eed02 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 5c39b80ed7de0b..7f91c2fde5096b 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 aa47d1d49929cb..904fd9a4af4e45 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 281e38c2b6c749..881ab8e379d4c6 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 From 1d5d4dbe810befe63e79b2d6cdcad2066e3b1fc4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 24 Apr 2012 01:55:30 -0400 Subject: [PATCH 51/55] 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 --- arch/score/kernel/signal.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c index a087ad85175a30..d4a49011c48a58 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(); + } } From 969a96168091f837645a674a9f7ed1a9aaa1424b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 24 Apr 2012 02:03:06 -0400 Subject: [PATCH 52/55] microblaze: handle TIF_NOTIFY_RESUME Signed-off-by: Al Viro --- arch/microblaze/kernel/entry-nommu.S | 12 +++++----- arch/microblaze/kernel/entry.S | 18 +++++++-------- arch/microblaze/kernel/signal.c | 34 +++++++++++++++++++--------- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S index f104d276b80641..ea2dd42fdc2228 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 66e34a3bfe1b41..3cee9130a3921f 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 fbdb02641821d7..449886db35a215 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(); + } +} From 8314019141e4f7274ea4dc264a47bbb2e17c66dd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 24 Apr 2012 02:21:18 -0400 Subject: [PATCH 53/55] microblaze: drop 'oldset' argument of do_notify_resume() never used... Signed-off-by: Al Viro --- arch/microblaze/kernel/entry-nommu.S | 4 +--- arch/microblaze/kernel/entry.S | 12 ++++-------- arch/microblaze/kernel/signal.c | 14 ++++++-------- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S index ea2dd42fdc2228..75c3ea1f48a123 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 3cee9130a3921f..daff9e5e4a1fb8 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 449886db35a215..7f4c7bef1642e0 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); From a53bb24e7666870bbc195e295a936aa0a58ce313 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 24 Apr 2012 02:30:16 -0400 Subject: [PATCH 54/55] xtensa: add handling of TIF_NOTIFY_RESUME Signed-off-by: Al Viro --- arch/xtensa/include/asm/thread_info.h | 1 + arch/xtensa/kernel/entry.S | 5 +++-- arch/xtensa/kernel/signal.c | 20 ++++++++++++++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/arch/xtensa/include/asm/thread_info.h b/arch/xtensa/include/asm/thread_info.h index 6abbedd09d85df..81abfd5d01acfd 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 @@ void do_signal(struct pt_regs *regs) 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(); + } +} From 415d04d08fec74b226c92c1fb54ad117c9c6bac4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 26 Apr 2012 18:17:28 -0400 Subject: [PATCH 55/55] unicore32: if there's no handler we need to restore sigmask, syscall or no syscall Signed-off-by: Al Viro --- arch/unicore32/kernel/signal.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c index 72d953190419de..7754df6ef7d454 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,