[RFC PATCH 4/8] signals: Remove sigmask() macro

From: Walt Drummond
Date: Mon Jan 03 2022 - 13:35:43 EST


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