The sigmask() macro can't support signals numbers larger than 64. Remove the general usage of sigmask() and bit masks as input into the functions that manipulate or accept sigset_t, with the exceptions of compatibility cases. Use a comma-separated list of signal numbers as input to sigaddset()/sigdelset()/... instead. Signed-off-by: Walt Drummond <walt@xxxxxxxxxxx> --- arch/alpha/kernel/signal.c | 4 +- arch/m68k/include/asm/signal.h | 6 +- arch/nios2/kernel/signal.c | 2 - arch/x86/include/asm/signal.h | 6 +- drivers/scsi/dpti.h | 2 - fs/ceph/addr.c | 2 +- fs/jffs2/background.c | 2 +- fs/lockd/svc.c | 1 - fs/signalfd.c | 2 +- include/linux/signal.h | 254 +++++++++++++++++++++------------ kernel/compat.c | 6 +- kernel/fork.c | 2 +- kernel/ptrace.c | 2 +- kernel/signal.c | 115 +++++++-------- virt/kvm/kvm_main.c | 2 +- 15 files changed, 238 insertions(+), 170 deletions(-) diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index bc077babafab..cae533594248 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -33,7 +33,7 @@ #define DEBUG_SIG 0 -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) +#define _BLOCKABLE (~(compat_sigmask(SIGKILL) | compat_sigmask(SIGSTOP))) asmlinkage void ret_from_sys_call(void); @@ -47,7 +47,7 @@ SYSCALL_DEFINE2(osf_sigprocmask, int, how, unsigned long, newmask) sigset_t mask; unsigned long res; - siginitset(&mask, newmask & _BLOCKABLE); + compat_siginitset(&mask, newmask & _BLOCKABLE); res = sigprocmask(how, &mask, &oldmask); if (!res) { force_successful_syscall_return(); diff --git a/arch/m68k/include/asm/signal.h b/arch/m68k/include/asm/signal.h index 8af85c38d377..464ff863c958 100644 --- a/arch/m68k/include/asm/signal.h +++ b/arch/m68k/include/asm/signal.h @@ -24,7 +24,7 @@ typedef struct { #ifndef CONFIG_CPU_HAS_NO_BITFIELDS #define __HAVE_ARCH_SIG_BITOPS -static inline void sigaddset(sigset_t *set, int _sig) +static inline void sigset_add(sigset_t *set, int _sig) { asm ("bfset %0{%1,#1}" : "+o" (*set) @@ -32,7 +32,7 @@ static inline void sigaddset(sigset_t *set, int _sig) : "cc"); } -static inline void sigdelset(sigset_t *set, int _sig) +static inline void sigset_del(sigset_t *set, int _sig) { asm ("bfclr %0{%1,#1}" : "+o" (*set) @@ -56,7 +56,7 @@ static inline int __gen_sigismember(sigset_t *set, int _sig) return ret; } -#define sigismember(set,sig) \ +#define sigset_ismember(set, sig) \ (__builtin_constant_p(sig) ? \ __const_sigismember(set,sig) : \ __gen_sigismember(set,sig)) diff --git a/arch/nios2/kernel/signal.c b/arch/nios2/kernel/signal.c index 2009ae2d3c3b..c9db511a6989 100644 --- a/arch/nios2/kernel/signal.c +++ b/arch/nios2/kernel/signal.c @@ -20,8 +20,6 @@ #include <asm/ucontext.h> #include <asm/cacheflush.h> -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - /* * Do a signal return; undo the signal stack. * diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h index 2dfb5fea13af..9bac7c6e524c 100644 --- a/arch/x86/include/asm/signal.h +++ b/arch/x86/include/asm/signal.h @@ -46,7 +46,7 @@ typedef sigset_t compat_sigset_t; #define __HAVE_ARCH_SIG_BITOPS -#define sigaddset(set,sig) \ +#define sigset_add(set, sig) \ (__builtin_constant_p(sig) \ ? __const_sigaddset((set), (sig)) \ : __gen_sigaddset((set), (sig))) @@ -62,7 +62,7 @@ static inline void __const_sigaddset(sigset_t *set, int _sig) set->sig[sig / _NSIG_BPW] |= 1 << (sig % _NSIG_BPW); } -#define sigdelset(set, sig) \ +#define sigset_del(set, sig) \ (__builtin_constant_p(sig) \ ? __const_sigdelset((set), (sig)) \ : __gen_sigdelset((set), (sig))) @@ -93,7 +93,7 @@ static inline int __gen_sigismember(sigset_t *set, int _sig) return ret; } -#define sigismember(set, sig) \ +#define sigset_ismember(set, sig) \ (__builtin_constant_p(sig) \ ? __const_sigismember((set), (sig)) \ : __gen_sigismember((set), (sig))) diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h index 8a079e8d7f65..cfcbb7d98fc0 100644 --- a/drivers/scsi/dpti.h +++ b/drivers/scsi/dpti.h @@ -96,8 +96,6 @@ static int adpt_device_reset(struct scsi_cmnd* cmd); #define PINFO(fmt, args...) printk(KERN_INFO fmt, ##args) #define PCRIT(fmt, args...) printk(KERN_CRIT fmt, ##args) -#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)) - // Command timeouts #define FOREVER (0) #define TMOUT_INQUIRY (20) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 99b80b5c7a93..238b5ce5ef64 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -1333,7 +1333,7 @@ const struct address_space_operations ceph_aops = { static void ceph_block_sigs(sigset_t *oldset) { sigset_t mask; - siginitsetinv(&mask, sigmask(SIGKILL)); + siginitsetinv(&mask, SIGKILL); sigprocmask(SIG_BLOCK, &mask, oldset); } diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 2b4d5013dc5d..bb84a8b2373c 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -77,7 +77,7 @@ static int jffs2_garbage_collect_thread(void *_c) struct jffs2_sb_info *c = _c; sigset_t hupmask; - siginitset(&hupmask, sigmask(SIGHUP)); + siginitset(&hupmask, SIGHUP); allow_signal(SIGKILL); allow_signal(SIGSTOP); allow_signal(SIGHUP); diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index b632be3ad57b..3c8b56c094d0 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -45,7 +45,6 @@ #define NLMDBG_FACILITY NLMDBG_SVC #define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE) -#define ALLOWED_SIGS (sigmask(SIGKILL)) static struct svc_program nlmsvc_program; diff --git a/fs/signalfd.c b/fs/signalfd.c index 12fdc282e299..ed024d5aad2a 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -270,7 +270,7 @@ static int do_signalfd4(int ufd, sigset_t *mask, int flags) if (flags & ~(SFD_CLOEXEC | SFD_NONBLOCK)) return -EINVAL; - sigdelsetmask(mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); + sigdelset(mask, SIGKILL, SIGSTOP); signotset(mask); if (ufd == -1) { diff --git a/include/linux/signal.h b/include/linux/signal.h index a730f3d4615e..eaf7991fffee 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -53,6 +53,12 @@ enum siginfo_layout { enum siginfo_layout siginfo_layout(unsigned sig, int si_code); +/* Test if 'sig' is valid signal. Use this instead of testing _NSIG directly */ +static inline int valid_signal(unsigned long sig) +{ + return sig <= _NSIG ? 1 : 0; +} + /* Test if 'sig' is a realtime signal. Use this instead of testing * SIGRTMIN/SIGRTMAX directly. */ @@ -62,15 +68,20 @@ static inline int realtime_signal(unsigned long sig) } /* - * Define some primitives to manipulate sigset_t. + * Define some primitives to manipulate individual bits in sigset_t. + * Don't use these directly. Architectures can define their own + * versions (see arch/x86/include/signal.h) */ #ifndef __HAVE_ARCH_SIG_BITOPS -#include <linux/bitops.h> +#define sigset_add(set, sig) __sigset_add(set, sig) +#define sigset_del(set, sig) __sigset_del(set, sig) +#define sigset_ismember(set, sig) __sigset_ismember(set, sig) +#endif /* We don't use <linux/bitops.h> for these because there is no need to be atomic. */ -static inline void sigaddset(sigset_t *set, int _sig) +static inline void __sigset_add(sigset_t *set, int _sig) { unsigned long sig = _sig - 1; if (_NSIG_WORDS == 1) @@ -79,7 +90,7 @@ static inline void sigaddset(sigset_t *set, int _sig) set->sig[sig / _NSIG_BPW] |= 1UL << (sig % _NSIG_BPW); } -static inline void sigdelset(sigset_t *set, int _sig) +static inline void __sigset_del(sigset_t *set, int _sig) { unsigned long sig = _sig - 1; if (_NSIG_WORDS == 1) @@ -88,33 +99,72 @@ static inline void sigdelset(sigset_t *set, int _sig) set->sig[sig / _NSIG_BPW] &= ~(1UL << (sig % _NSIG_BPW)); } -static inline int sigismember(sigset_t *set, int _sig) +static inline int __sigset_ismember(sigset_t *set, int _sig) { unsigned long sig = _sig - 1; if (_NSIG_WORDS == 1) - return 1 & (set->sig[0] >> sig); + return 1UL & (set->sig[0] >> sig); else - return 1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW)); + return 1UL & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW)); } -#endif /* __HAVE_ARCH_SIG_BITOPS */ +/* Some primitives for setting/deleting signals from sigset_t. Use these. */ -static inline int sigisemptyset(sigset_t *set) +#define NUM_INTARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int)) + +#define sigdelset(x, ...) __sigdelset((x), NUM_INTARGS(__VA_ARGS__), \ + __VA_ARGS__) +static inline void __sigdelset(sigset_t *set, int count, ...) { - switch (_NSIG_WORDS) { - case 4: - return (set->sig[3] | set->sig[2] | - set->sig[1] | set->sig[0]) == 0; - case 2: - return (set->sig[1] | set->sig[0]) == 0; - case 1: - return set->sig[0] == 0; - default: - BUILD_BUG(); - return 0; + va_list ap; + int sig; + + va_start(ap, count); + while (count > 0) { + sig = va_arg(ap, int); + if (valid_signal(sig) && sig != 0) + sigset_del(set, sig); + count--; } + va_end(ap); +} + +#define sigaddset(x, ...) __sigaddset((x), NUM_INTARGS(__VA_ARGS__), \ + __VA_ARGS__) +static inline void __sigaddset(sigset_t *set, int count, ...) +{ + va_list ap; + int sig; + + va_start(ap, count); + while (count > 0) { + sig = va_arg(ap, int); + if (valid_signal(sig) && sig != 0) + sigset_add(set, sig); + count--; + } + va_end(ap); +} + +static inline int sigismember(sigset_t *set, int sig) +{ + if (!valid_signal(sig) || sig == 0) + return 0; + return sigset_ismember(set, sig); } +#define siginitset(set, ...) \ +do { \ + sigemptyset((set)); \ + sigaddset((set), __VA_ARGS__); \ +} while (0) + +#define siginitsetinv(set, ...) \ +do { \ + sigfillset((set)); \ + sigdelset((set), __VA_ARGS__); \ +} while (0) + static inline int sigequalsets(const sigset_t *set1, const sigset_t *set2) { switch (_NSIG_WORDS) { @@ -128,11 +178,18 @@ static inline int sigequalsets(const sigset_t *set1, const sigset_t *set2) (set1->sig[0] == set2->sig[0]); case 1: return set1->sig[0] == set2->sig[0]; + default: + return memcmp(set1, set2, sizeof(sigset_t)) == 0; } return 0; } -#define sigmask(sig) (1UL << ((sig) - 1)) +static inline int sigisemptyset(sigset_t *set) +{ + sigset_t empty = {0}; + + return sigequalsets(set, &empty); +} #ifndef __HAVE_ARCH_SIG_SETOPS #include <linux/string.h> @@ -141,6 +198,7 @@ static inline int sigequalsets(const sigset_t *set1, const sigset_t *set2) static inline void name(sigset_t *r, const sigset_t *a, const sigset_t *b) \ { \ unsigned long a0, a1, a2, a3, b0, b1, b2, b3; \ + int i; \ \ switch (_NSIG_WORDS) { \ case 4: \ @@ -158,7 +216,9 @@ static inline void name(sigset_t *r, const sigset_t *a, const sigset_t *b) \ r->sig[0] = op(a0, b0); \ break; \ default: \ - BUILD_BUG(); \ + for (i = 0; i < _NSIG_WORDS; i++) \ + r->sig[i] = op(a->sig[i], b->sig[i]); \ + break; \ } \ } @@ -179,6 +239,8 @@ _SIG_SET_BINOP(sigandnsets, _sig_andn) #define _SIG_SET_OP(name, op) \ static inline void name(sigset_t *set) \ { \ + int i; \ + \ switch (_NSIG_WORDS) { \ case 4: set->sig[3] = op(set->sig[3]); \ set->sig[2] = op(set->sig[2]); \ @@ -188,7 +250,9 @@ static inline void name(sigset_t *set) \ case 1: set->sig[0] = op(set->sig[0]); \ break; \ default: \ - BUILD_BUG(); \ + for (i = 0; i < _NSIG_WORDS; i++) \ + set->sig[i] = op(set->sig[i]); \ + break; \ } \ } @@ -224,24 +288,13 @@ static inline void sigfillset(sigset_t *set) } } -/* Some extensions for manipulating the low 32 signals in particular. */ +#endif /* __HAVE_ARCH_SIG_SETOPS */ -static inline void sigaddsetmask(sigset_t *set, unsigned long mask) -{ - set->sig[0] |= mask; -} +/* Primitives for handing the compat (first long) sigset_t */ -static inline void sigdelsetmask(sigset_t *set, unsigned long mask) -{ - set->sig[0] &= ~mask; -} +#define compat_sigmask(sig) (1UL << ((sig) - 1)) -static inline int sigtestsetmask(sigset_t *set, unsigned long mask) -{ - return (set->sig[0] & mask) != 0; -} - -static inline void siginitset(sigset_t *set, unsigned long mask) +static inline void compat_siginitset(sigset_t *set, unsigned long mask) { set->sig[0] = mask; switch (_NSIG_WORDS) { @@ -254,7 +307,7 @@ static inline void siginitset(sigset_t *set, unsigned long mask) } } -static inline void siginitsetinv(sigset_t *set, unsigned long mask) +static inline void compat_siginitsetinv(sigset_t *set, unsigned long mask) { set->sig[0] = ~mask; switch (_NSIG_WORDS) { @@ -267,7 +320,21 @@ static inline void siginitsetinv(sigset_t *set, unsigned long mask) } } -#endif /* __HAVE_ARCH_SIG_SETOPS */ +static inline void compat_sigaddsetmask(sigset_t *set, unsigned long mask) +{ + set->sig[0] |= mask; +} + +static inline void compat_sigdelsetmask(sigset_t *set, unsigned long mask) +{ + set->sig[0] &= ~mask; +} + +static inline int compat_sigtestsetmask(sigset_t *set, unsigned long mask) +{ + return (set->sig[0] & mask) != 0; +} + /* Safely copy a sigset_t from user space handling any differences in * size between user space and kernel sigset_t. We don't use @@ -338,12 +405,6 @@ static inline void init_sigpending(struct sigpending *sig) extern void flush_sigqueue(struct sigpending *queue); -/* Test if 'sig' is valid signal. Use this instead of testing _NSIG directly */ -static inline int valid_signal(unsigned long sig) -{ - return sig <= _NSIG ? 1 : 0; -} - struct timespec; struct pt_regs; enum pid_type; @@ -470,55 +531,72 @@ extern bool unhandled_signal(struct task_struct *tsk, int sig); * default action of stopping the process may happen later or never. */ +static inline int sig_kernel_stop(unsigned long sig) +{ + return sig == SIGSTOP || + sig == SIGTSTP || + sig == SIGTTIN || + sig == SIGTTOU; +} + +static inline int sig_kernel_ignore(unsigned long sig) +{ + return sig == SIGCONT || + sig == SIGCHLD || + sig == SIGWINCH || + sig == SIGURG; +} + +static inline int sig_kernel_only(unsigned long sig) +{ + return sig == SIGKILL || + sig == SIGSTOP; +} + +static inline int sig_kernel_coredump(unsigned long sig) +{ + return sig == SIGQUIT || + sig == SIGILL || + sig == SIGTRAP || + sig == SIGABRT || + sig == SIGFPE || + sig == SIGSEGV || + sig == SIGBUS || + sig == SIGSYS || + sig == SIGXCPU || #ifdef SIGEMT -#define SIGEMT_MASK rt_sigmask(SIGEMT) -#else -#define SIGEMT_MASK 0 + sig == SIGEMT || #endif + sig == SIGXFSZ; +} -#if SIGRTMIN > BITS_PER_LONG -#define rt_sigmask(sig) (1ULL << ((sig)-1)) -#else -#define rt_sigmask(sig) sigmask(sig) +static inline int sig_specific_sicodes(unsigned long sig) +{ + return sig == SIGILL || + sig == SIGFPE || + sig == SIGSEGV || + sig == SIGBUS || + sig == SIGTRAP || + sig == SIGCHLD || + sig == SIGPOLL || +#ifdef SIGEMT + sig == SIGEMT || #endif + sig == SIGSYS; +} -#define siginmask(sig, mask) \ - ((sig) > 0 && (sig) < SIGRTMIN && (rt_sigmask(sig) & (mask))) - -#define SIG_KERNEL_ONLY_MASK (\ - rt_sigmask(SIGKILL) | rt_sigmask(SIGSTOP)) - -#define SIG_KERNEL_STOP_MASK (\ - rt_sigmask(SIGSTOP) | rt_sigmask(SIGTSTP) | \ - rt_sigmask(SIGTTIN) | rt_sigmask(SIGTTOU) ) - -#define SIG_KERNEL_COREDUMP_MASK (\ - rt_sigmask(SIGQUIT) | rt_sigmask(SIGILL) | \ - rt_sigmask(SIGTRAP) | rt_sigmask(SIGABRT) | \ - rt_sigmask(SIGFPE) | rt_sigmask(SIGSEGV) | \ - rt_sigmask(SIGBUS) | rt_sigmask(SIGSYS) | \ - rt_sigmask(SIGXCPU) | rt_sigmask(SIGXFSZ) | \ - SIGEMT_MASK ) - -#define SIG_KERNEL_IGNORE_MASK (\ - rt_sigmask(SIGCONT) | rt_sigmask(SIGCHLD) | \ - rt_sigmask(SIGWINCH) | rt_sigmask(SIGURG) ) - -#define SIG_SPECIFIC_SICODES_MASK (\ - rt_sigmask(SIGILL) | rt_sigmask(SIGFPE) | \ - rt_sigmask(SIGSEGV) | rt_sigmask(SIGBUS) | \ - rt_sigmask(SIGTRAP) | rt_sigmask(SIGCHLD) | \ - rt_sigmask(SIGPOLL) | rt_sigmask(SIGSYS) | \ - SIGEMT_MASK ) - -#define sig_kernel_only(sig) siginmask(sig, SIG_KERNEL_ONLY_MASK) -#define sig_kernel_coredump(sig) siginmask(sig, SIG_KERNEL_COREDUMP_MASK) -#define sig_kernel_ignore(sig) siginmask(sig, SIG_KERNEL_IGNORE_MASK) -#define sig_kernel_stop(sig) siginmask(sig, SIG_KERNEL_STOP_MASK) -#define sig_specific_sicodes(sig) siginmask(sig, SIG_SPECIFIC_SICODES_MASK) +static inline int synchronous_signal(unsigned long sig) +{ + return sig == SIGSEGV || + sig == SIGBUS || + sig == SIGILL || + sig == SIGTRAP || + sig == SIGFPE || + sig == SIGSYS; +} #define sig_fatal(t, signr) \ - (!siginmask(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \ + (!(sig_kernel_ignore(signr) || sig_kernel_stop(signr)) && \ (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL) void signals_init(void); diff --git a/kernel/compat.c b/kernel/compat.c index cc2438f4070c..26ffd271444c 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -49,16 +49,16 @@ COMPAT_SYSCALL_DEFINE3(sigprocmask, int, how, if (nset) { if (get_user(new_set, nset)) return -EFAULT; - new_set &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP)); + new_set &= ~(compat_sigmask(SIGKILL) | compat_sigmask(SIGSTOP)); new_blocked = current->blocked; switch (how) { case SIG_BLOCK: - sigaddsetmask(&new_blocked, new_set); + compat_sigaddsetmask(&new_blocked, new_set); break; case SIG_UNBLOCK: - sigdelsetmask(&new_blocked, new_set); + compat_sigdelsetmask(&new_blocked, new_set); break; case SIG_SETMASK: compat_sig_setmask(&new_blocked, new_set); diff --git a/kernel/fork.c b/kernel/fork.c index 38681ad44c76..8b07f0090b82 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -2032,7 +2032,7 @@ static __latent_entropy struct task_struct *copy_process( * fatal or STOP */ p->flags |= PF_IO_WORKER; - siginitsetinv(&p->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP)); + siginitsetinv(&p->blocked, SIGKILL, SIGSTOP); } /* diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 2f7ee345a629..200b99d39878 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -1102,7 +1102,7 @@ int ptrace_request(struct task_struct *child, long request, if (ret) break; - sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); + sigdelset(&new_set, SIGKILL, SIGSTOP); /* * Every thread does recalc_sigpending() after resume, so diff --git a/kernel/signal.c b/kernel/signal.c index a2f0e38ba934..9421f1112b20 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -64,6 +64,9 @@ static struct kmem_cache *sigqueue_cachep; int print_fatal_signals __read_mostly; +sigset_t signal_stop_mask; +sigset_t signal_synchronous_mask; + static void __user *sig_handler(struct task_struct *t, int sig) { return t->sighand->action[sig - 1].sa.sa_handler; @@ -199,55 +202,26 @@ void calculate_sigpending(void) } /* Given the mask, find the first available signal that should be serviced. */ - -#define SYNCHRONOUS_MASK \ - (sigmask(SIGSEGV) | sigmask(SIGBUS) | sigmask(SIGILL) | \ - sigmask(SIGTRAP) | sigmask(SIGFPE) | sigmask(SIGSYS)) - int next_signal(struct sigpending *pending, sigset_t *mask) { - unsigned long i, *s, *m, x; - int sig = 0; + int i, sig; + sigset_t pend, s; - s = pending->signal.sig; - m = mask->sig; + sigandnsets(&pend, &pending->signal, mask); - /* - * Handle the first word specially: it contains the - * synchronous signals that need to be dequeued first. - */ - x = *s &~ *m; - if (x) { - if (x & SYNCHRONOUS_MASK) - x &= SYNCHRONOUS_MASK; - sig = ffz(~x) + 1; - return sig; - } + /* Handle synchronous signals first */ + sigandsets(&s, &pend, &signal_synchronous_mask); + if (!sigisemptyset(&s)) + pend = s; - switch (_NSIG_WORDS) { - default: - for (i = 1; i < _NSIG_WORDS; ++i) { - x = *++s &~ *++m; - if (!x) - continue; - sig = ffz(~x) + i*_NSIG_BPW + 1; - break; + for (i = 0; i < _NSIG_WORDS; i++) { + if (pend.sig[i] != 0) { + sig = ffz(~pend.sig[i]) + i*_NSIG_BPW + 1; + return sig; } - break; - - case 2: - x = s[1] &~ m[1]; - if (!x) - break; - sig = ffz(~x) + _NSIG_BPW + 1; - break; - - case 1: - /* Nothing to do */ - break; } - return sig; + return 0; } static inline void print_dropped_signal(int sig) @@ -709,11 +683,14 @@ static int dequeue_synchronous_signal(kernel_siginfo_t *info) struct task_struct *tsk = current; struct sigpending *pending = &tsk->pending; struct sigqueue *q, *sync = NULL; + sigset_t s; /* * Might a synchronous signal be in the queue? */ - if (!((pending->signal.sig[0] & ~tsk->blocked.sig[0]) & SYNCHRONOUS_MASK)) + sigandnsets(&s, &pending->signal, &tsk->blocked); + sigandsets(&s, &s, &signal_synchronous_mask); + if (sigisemptyset(&s)) return 0; /* @@ -722,7 +699,7 @@ static int dequeue_synchronous_signal(kernel_siginfo_t *info) list_for_each_entry(q, &pending->list, list) { /* Synchronous signals have a positive si_code */ if ((q->info.si_code > SI_USER) && - (sigmask(q->info.si_signo) & SYNCHRONOUS_MASK)) { + synchronous_signal(q->info.si_signo)) { sync = q; goto next; } @@ -795,6 +772,25 @@ static void flush_sigqueue_mask(sigset_t *mask, struct sigpending *s) } } +#define flush_sigqueue_sig(x, ...) __flush_sigqueue_sig((x), \ + NUM_INTARGS(__VA_ARGS__), __VA_ARGS__) +static void __flush_sigqueue_sig(struct sigpending *s, int count, ...) +{ + va_list ap; + sigset_t mask; + int sig; + + sigemptyset(&mask); + va_start(ap, count); + while (count > 0) { + sig = va_arg(ap, int); + if (valid_signal(sig) && sig != 0) + sigset_add(&mask, sig); + count--; + } + flush_sigqueue_mask(&mask, s); +} + static inline int is_si_special(const struct kernel_siginfo *info) { return info <= SEND_SIG_PRIV; @@ -913,8 +909,7 @@ static bool prepare_signal(int sig, struct task_struct *p, bool force) /* * This is a stop signal. Remove SIGCONT from all queues. */ - siginitset(&flush, sigmask(SIGCONT)); - flush_sigqueue_mask(&flush, &signal->shared_pending); + flush_sigqueue_sig(&signal->shared_pending, SIGCONT); for_each_thread(p, t) flush_sigqueue_mask(&flush, &t->pending); } else if (sig == SIGCONT) { @@ -922,10 +917,9 @@ static bool prepare_signal(int sig, struct task_struct *p, bool force) /* * Remove all stop signals from all queues, wake all threads. */ - siginitset(&flush, SIG_KERNEL_STOP_MASK); - flush_sigqueue_mask(&flush, &signal->shared_pending); + flush_sigqueue_mask(&signal_stop_mask, &signal->shared_pending); for_each_thread(p, t) { - flush_sigqueue_mask(&flush, &t->pending); + flush_sigqueue_mask(&signal_stop_mask, &t->pending); task_clear_jobctl_pending(t, JOBCTL_STOP_PENDING); if (likely(!(t->ptrace & PT_SEIZED))) wake_up_state(t, __TASK_STOPPED); @@ -1172,7 +1166,7 @@ static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struc sigset_t *signal = &delayed->signal; /* Can't queue both a stop and a continue signal */ if (sig == SIGCONT) - sigdelsetmask(signal, SIG_KERNEL_STOP_MASK); + sigandnsets(signal, signal, &signal_stop_mask); else if (sig_kernel_stop(sig)) sigdelset(signal, SIGCONT); sigaddset(signal, sig); @@ -3023,7 +3017,7 @@ static void __set_task_blocked(struct task_struct *tsk, const sigset_t *newset) */ void set_current_blocked(sigset_t *newset) { - sigdelsetmask(newset, sigmask(SIGKILL) | sigmask(SIGSTOP)); + sigdelset(newset, SIGKILL, SIGSTOP); __set_current_blocked(newset); } @@ -3150,7 +3144,7 @@ SYSCALL_DEFINE4(rt_sigprocmask, int, how, sigset_t __user *, nset, if (nset) { if (copy_sigset_from_user(&new_set, nset, sigsetsize)) return -EFAULT; - sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); + sigdelset(&new_set, SIGKILL, SIGSTOP); error = sigprocmask(how, &new_set, NULL); if (error) @@ -3180,7 +3174,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigprocmask, int, how, compat_sigset_t __user *, nset, if (nset) { if (copy_compat_sigset_from_user(&new_set, nset, sigsetsize)) return -EFAULT; - sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); + sigdelset(&new_set, SIGKILL, SIGSTOP); error = sigprocmask(how, &new_set, NULL); if (error) @@ -3586,7 +3580,7 @@ static int do_sigtimedwait(const sigset_t *which, kernel_siginfo_t *info, /* * Invert the set of allowed signals to get those we want to block. */ - sigdelsetmask(&mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); + sigdelset(&mask, SIGKILL, SIGSTOP); signotset(&mask); spin_lock_irq(&tsk->sighand->siglock); @@ -4111,8 +4105,7 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) sigaction_compat_abi(act, oact); if (act) { - sigdelsetmask(&act->sa.sa_mask, - sigmask(SIGKILL) | sigmask(SIGSTOP)); + sigdelset(&act->sa.sa_mask, SIGKILL, SIGSTOP); *k = *act; /* * POSIX 3.3.1.3: @@ -4126,9 +4119,7 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) * be discarded, whether or not it is blocked" */ if (sig_handler_ignored(sig_handler(p, sig), sig)) { - sigemptyset(&mask); - sigaddset(&mask, sig); - flush_sigqueue_mask(&mask, &p->signal->shared_pending); + flush_sigqueue_sig(&p->signal->shared_pending, sig); for_each_thread(p, t) flush_sigqueue_mask(&mask, &t->pending); } @@ -4332,10 +4323,10 @@ SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, nset, switch (how) { case SIG_BLOCK: - sigaddsetmask(&new_blocked, new_set); + compat_sigaddsetmask(&new_blocked, new_set); break; case SIG_UNBLOCK: - sigdelsetmask(&new_blocked, new_set); + compat_sigdelsetmask(&new_blocked, new_set); break; case SIG_SETMASK: new_blocked.sig[0] = new_set; @@ -4724,6 +4715,10 @@ void __init signals_init(void) { siginfo_buildtime_checks(); + sigaddset(&signal_stop_mask, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU); + sigaddset(&signal_synchronous_mask, SIGSEGV, SIGBUS, SIGILL, SIGTRAP, + SIGFPE, SIGSYS); + sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC | SLAB_ACCOUNT); } diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index c8b3645c9a7d..ab6ba4ec661b 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -3684,7 +3684,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset) { if (sigset) { - sigdelsetmask(sigset, sigmask(SIGKILL)|sigmask(SIGSTOP)); + sigdelset(sigset, SIGKILL, SIGSTOP); vcpu->sigset_active = 1; vcpu->sigset = *sigset; } else -- 2.30.2