From nobody Wed Jul 1 03:09:27 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6A0E9C433EF for ; Mon, 3 Jan 2022 18:35:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235673AbiACSfH (ORCPT ); Mon, 3 Jan 2022 13:35:07 -0500 Received: from drummond.us ([74.95.14.229]:40377 "EHLO talisker.home.drummond.us" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235703AbiACSfC (ORCPT ); Mon, 3 Jan 2022 13:35:02 -0500 X-Greylist: delayed 836 seconds by postgrey-1.27 at vger.kernel.org; Mon, 03 Jan 2022 13:34:55 EST Received: from talisker.home.drummond.us (localhost [127.0.0.1]) by talisker.home.drummond.us (8.15.2/8.15.2/Debian-20) with ESMTP id 203IKWH6983492; Mon, 3 Jan 2022 10:20:32 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=home.drummond.us; s=default; t=1641234032; bh=s0/ZBp9Jrtlt/uuSXSFQcrmEVihhU+gaTmMV80bD7Vk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GQhAKvpJMy7NCbgHgjLqOk8bgZX3S+KH52GLsgvI3GmlwB1DChH30sUNhgIvpvgt9 HVN0P+YwVKbaIXk2Z3aIowaP18Hxs4CBD2QZHHJOF1qPM9lEMLuUdiDOaD0+yksxIe a5mAgFp8dD545UVdCRWUvGJqYqMNzlhLd3m0D8AVJCr5ItcRGcj0HJevqga7i/VQ9k KyqK1cvlqktZ0WWgL4g5mmW0U6DqU6ysFR6t9WSkfUYqiFBI/Yq9IiisQAIH+K/Rmq s/EqkY2v3XWZttQbGkF5QEBMWjFS16B8OLRUUUiGUft0xNyMgWa9R0hi5yu3dSMwT1 2j/1J/Ep0lpZQ== Received: (from walt@localhost) by talisker.home.drummond.us (8.15.2/8.15.2/Submit) id 203IKW7q983491; Mon, 3 Jan 2022 10:20:32 -0800 From: Walt Drummond To: Alexander Viro , Oleg Nesterov , Paolo Bonzini Cc: linux-kernel@vger.kernel.org, Walt Drummond , linux-fsdevel@vger.kernel.org, kvm@vger.kernel.org Subject: [RFC PATCH 1/8] signals: Make the real-time signal system calls accept different sized sigset_t from user space. Date: Mon, 3 Jan 2022 10:19:49 -0800 Message-Id: <20220103181956.983342-2-walt@drummond.us> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220103181956.983342-1-walt@drummond.us> References: <20220103181956.983342-1-walt@drummond.us> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The real-time signals API provides a mechanism for user space to tell the kernel how many bytes is has in sigset_t. Make these system calls use that mechanism and accept differently sized sigset_t. Add a value to the auxvec to inform user space of the maximum size sigset_t the kernel can accept. Signed-off-by: Walt Drummond --- fs/binfmt_elf.c | 1 + fs/binfmt_elf_fdpic.c | 1 + fs/signalfd.c | 24 +++--- include/linux/compat.h | 98 +++++++++++++++++++++--- include/linux/signal.h | 62 +++++++++++++++ include/uapi/linux/auxvec.h | 1 + kernel/compat.c | 24 ------ kernel/ptrace.c | 16 ++-- kernel/signal.c | 147 +++++++++++++++++++----------------- virt/kvm/kvm_main.c | 16 ++-- 10 files changed, 257 insertions(+), 133 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index a813b70f594e..7133515fd386 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -274,6 +274,7 @@ create_elf_tables(struct linux_binprm *bprm, const stru= ct elfhdr *exec, #ifdef ELF_HWCAP2 NEW_AUX_ENT(AT_HWCAP2, ELF_HWCAP2); #endif + NEW_AUX_ENT(AT_SIGSET_SZ, SIGSETSIZE_MAX); NEW_AUX_ENT(AT_EXECFN, bprm->exec); if (k_platform) { NEW_AUX_ENT(AT_PLATFORM, diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 6d8fd6030cbb..09249dc4364b 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -659,6 +659,7 @@ static int create_elf_fdpic_tables(struct linux_binprm = *bprm, NEW_AUX_ENT(AT_EGID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->e= gid)); NEW_AUX_ENT(AT_SECURE, bprm->secureexec); NEW_AUX_ENT(AT_EXECFN, bprm->exec); + NEW_AUX_ENT(AT_SIGSET_SZ, SIGSETSIZE_MAX); =20 #ifdef ARCH_DLINFO nr =3D 0; diff --git a/fs/signalfd.c b/fs/signalfd.c index 040e1cf90528..12fdc282e299 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -311,24 +311,24 @@ static int do_signalfd4(int ufd, sigset_t *mask, int = flags) SYSCALL_DEFINE4(signalfd4, int, ufd, sigset_t __user *, user_mask, size_t, sizemask, int, flags) { + int ret; sigset_t mask; =20 - if (sizemask !=3D sizeof(sigset_t)) - return -EINVAL; - if (copy_from_user(&mask, user_mask, sizeof(mask))) - return -EFAULT; + ret =3D copy_sigset_from_user(&mask, user_mask, sizemask); + if (ret) + return ret; return do_signalfd4(ufd, &mask, flags); } =20 SYSCALL_DEFINE3(signalfd, int, ufd, sigset_t __user *, user_mask, size_t, sizemask) { + int ret; sigset_t mask; =20 - if (sizemask !=3D sizeof(sigset_t)) - return -EINVAL; - if (copy_from_user(&mask, user_mask, sizeof(mask))) - return -EFAULT; + ret =3D copy_sigset_from_user(&mask, user_mask, sizemask); + if (ret) + return ret; return do_signalfd4(ufd, &mask, 0); } =20 @@ -338,11 +338,11 @@ static long do_compat_signalfd4(int ufd, compat_size_t sigsetsize, int flags) { sigset_t mask; + int ret; =20 - if (sigsetsize !=3D sizeof(compat_sigset_t)) - return -EINVAL; - if (get_compat_sigset(&mask, user_mask)) - return -EFAULT; + ret =3D copy_compat_sigset_from_user(&mask, user_mask, sigsetsize); + if (ret) + return ret; return do_signalfd4(ufd, &mask, flags); } =20 diff --git a/include/linux/compat.h b/include/linux/compat.h index 1c758b0e0359..ecdbff1d2218 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -407,33 +407,109 @@ int __copy_siginfo_to_user32(struct compat_siginfo _= _user *to, int get_compat_sigevent(struct sigevent *event, const struct compat_sigevent __user *u_event); =20 -extern int get_compat_sigset(sigset_t *set, const compat_sigset_t __user *= compat); - /* * Defined inline such that size can be compile time constant, which avoids * CONFIG_HARDENED_USERCOPY complaining about copies from task_struct */ static inline int -put_compat_sigset(compat_sigset_t __user *compat, const sigset_t *set, - unsigned int size) +copy_compat_sigset_to_user(compat_sigset_t __user *compat, const sigset_t = *set, + size_t sigsetsize) { - /* size <=3D sizeof(compat_sigset_t) <=3D sizeof(sigset_t) */ + size_t copybytes; #if defined(__BIG_ENDIAN) && defined(CONFIG_64BIT) compat_sigset_t v; + int i; +#endif + + if (!valid_sigsetsize(sigsetsize)) + return -EINVAL; + + copybytes =3D min(sizeof(compat_sigset_t), sigsetsize); + +#if defined(__BIG_ENDIAN) && defined(CONFIG_64BIT) + switch (_NSIG_WORDS) { + default: + for (i =3D 0; i < _NSIG_WORDS; i++) { + v.sig[(i * 2)] =3D set->sig[i]; + v.sig[(i * 2) + 1] =3D set->sig[i] >> 32; + } + break; + case 4: + v.sig[7] =3D (set->sig[3] >> 32); + v.sig[6] =3D set->sig[3]; + fallthrough; + case 3: + v.sig[5] =3D (set->sig[2] >> 32); + v.sig[4] =3D set->sig[2]; + fallthrough; + case 2: + v.sig[3] =3D (set->sig[1] >> 32); + v.sig[2] =3D set->sig[1]; + fallthrough; + case 1: + v.sig[1] =3D (set->sig[0] >> 32); + v.sig[0] =3D set->sig[0]; + } + if (copy_to_user(compat, &v, copybytes)) + return -EFAULT; +#else + if (copy_to_user(compat, set, copybytes)) + return -EFAULT; +#endif + /* Zero any unused part of mask */ + if (sigsetsize > sizeof(compat_sigset_t)) { + if (clear_user((char *)compat + copybytes, + sigsetsize - sizeof(compat_sigset_t))) + return -EFAULT; + } + + return 0; +} +#define put_compat_sigset(set, compat, size) \ + copy_compat_sigset_to_user((set), (compat), (size)) + +static inline int +copy_compat_sigset_from_user(sigset_t *set, + const compat_sigset_t __user *compat, size_t size) +{ +#if defined(__BIG_ENDIAN) && defined(CONFIG_64BIT) + compat_sigset_t v; + int i; +#endif + + if (!valid_sigsetsize(size)) + return -EINVAL; + +#if defined(__BIG_ENDIAN) && defined(CONFIG_64BIT) + if (copy_from_user(&v, compat, min(sizeof(compat_sigset_t), size))) + return -EFAULT; switch (_NSIG_WORDS) { - case 4: v.sig[7] =3D (set->sig[3] >> 32); v.sig[6] =3D set->sig[3]; + default: + for (i =3D 0; i < _NSIG_WORDS; i++) { + set->sig[i] =3D v.sig[(i * 2)] | + (((long) v.sig[(i * 2) + 1]) << 32); + } + break; + case 4: + set->sig[3] =3D v.sig[6] | (((long)v.sig[7]) << 32); fallthrough; - case 3: v.sig[5] =3D (set->sig[2] >> 32); v.sig[4] =3D set->sig[2]; + case 3: + set->sig[2] =3D v.sig[4] | (((long)v.sig[5]) << 32); fallthrough; - case 2: v.sig[3] =3D (set->sig[1] >> 32); v.sig[2] =3D set->sig[1]; + case 2: + set->sig[1] =3D v.sig[2] | (((long)v.sig[3]) << 32); fallthrough; - case 1: v.sig[1] =3D (set->sig[0] >> 32); v.sig[0] =3D set->sig[0]; + case 1: + set->sig[0] =3D v.sig[0] | (((long)v.sig[1]) << 32); } - return copy_to_user(compat, &v, size) ? -EFAULT : 0; #else - return copy_to_user(compat, set, size) ? -EFAULT : 0; + if (copy_from_user(set, compat, min(sizeof(compat_sigset_t), size))) + return -EFAULT; #endif + return 0; } +#define get_compat_sigset(set, compat) \ + copy_compat_sigset_from_user((set), (compat), sizeof(compat_sigset_t)) =20 #ifdef CONFIG_CPU_BIG_ENDIAN #define unsafe_put_compat_sigset(compat, set, label) do { \ diff --git a/include/linux/signal.h b/include/linux/signal.h index 3f96a6374e4f..c66d4f520228 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -5,6 +5,7 @@ #include #include #include +#include =20 struct task_struct; =20 @@ -260,6 +261,67 @@ static inline void siginitsetinv(sigset_t *set, unsign= ed long mask) =20 #endif /* __HAVE_ARCH_SIG_SETOPS */ =20 +/* Safely copy a sigset_t from user space handling any differences in + * size between user space and kernel sigset_t. We don't use + * copy_struct_from_user() here as we can't ensure that in the case + * where sigisetsize > sizeof(sigset_t), the unused bytes are zeroed. + * + * SIGSETSIZE_MIN *must* be 8 bytes and cannot change. + * + * SIGSETSIZE_MAX shouldn't be too small, nor should it be too large. + * We've somewhat randomly picked 128 bytes to keep this sync'ed with + * glibc and musl; this can be changed as needed. + */ + +#define SIGSETSIZE_MIN 8 +#define SIGSETSIZE_MAX 128 + +static inline int valid_sigsetsize(size_t sigsetsize) +{ + return sigsetsize >=3D SIGSETSIZE_MIN && + sigsetsize <=3D SIGSETSIZE_MAX; +} + +static inline int copy_sigset_from_user(sigset_t *kmask, + const sigset_t __user *umask, + size_t sigsetsize) +{ + if (!valid_sigsetsize(sigsetsize)) + return -EINVAL; + + if (kmask =3D=3D NULL) + return -EFAULT; + + sigemptyset(kmask); + + if (copy_from_user(kmask, umask, min(sizeof(sigset_t), sigsetsize))) + return -EFAULT; + + return 0; +} + +static inline int copy_sigset_to_user(sigset_t __user *umask, + sigset_t *kmask, + size_t sigsetsize) +{ + size_t copybytes; + + if (!valid_sigsetsize(sigsetsize)) + return -EINVAL; + + copybytes =3D min(sizeof(sigset_t), sigsetsize); + if (copy_to_user(umask, kmask, copybytes)) + return -EFAULT; + + /* Zero unused parts of umask */ + if (sigsetsize > copybytes) { + if (clear_user((char *)umask + copybytes, + sigsetsize - copybytes)) + return -EFAULT; + } + return 0; +} + static inline void init_sigpending(struct sigpending *sig) { sigemptyset(&sig->signal); diff --git a/include/uapi/linux/auxvec.h b/include/uapi/linux/auxvec.h index c7e502bf5a6f..752184abf620 100644 --- a/include/uapi/linux/auxvec.h +++ b/include/uapi/linux/auxvec.h @@ -30,6 +30,7 @@ * differ from AT_PLATFORM. */ #define AT_RANDOM 25 /* address of 16 random bytes */ #define AT_HWCAP2 26 /* extension of AT_HWCAP */ +#define AT_SIGSET_SZ 27 /* sizeof(sigset_t) */ =20 #define AT_EXECFN 31 /* filename of program */ =20 diff --git a/kernel/compat.c b/kernel/compat.c index 55551989d9da..cc2438f4070c 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -245,27 +245,3 @@ long compat_put_bitmap(compat_ulong_t __user *umask, u= nsigned long *mask, user_write_access_end(); return -EFAULT; } - -int -get_compat_sigset(sigset_t *set, const compat_sigset_t __user *compat) -{ -#ifdef __BIG_ENDIAN - compat_sigset_t v; - if (copy_from_user(&v, compat, sizeof(compat_sigset_t))) - return -EFAULT; - switch (_NSIG_WORDS) { - case 4: set->sig[3] =3D v.sig[6] | (((long)v.sig[7]) << 32 ); - fallthrough; - case 3: set->sig[2] =3D v.sig[4] | (((long)v.sig[5]) << 32 ); - fallthrough; - case 2: set->sig[1] =3D v.sig[2] | (((long)v.sig[3]) << 32 ); - fallthrough; - case 1: set->sig[0] =3D v.sig[0] | (((long)v.sig[1]) << 32 ); - } -#else - if (copy_from_user(set, compat, sizeof(compat_sigset_t))) - return -EFAULT; -#endif - return 0; -} -EXPORT_SYMBOL_GPL(get_compat_sigset); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index f8589bf8d7dc..2f7ee345a629 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -1074,8 +1074,9 @@ int ptrace_request(struct task_struct *child, long re= quest, =20 case PTRACE_GETSIGMASK: { sigset_t *mask; + size_t sigsetsize =3D (size_t) addr; =20 - if (addr !=3D sizeof(sigset_t)) { + if (!valid_sigsetsize(sigsetsize) =3D=3D 0) { ret =3D -EINVAL; break; } @@ -1085,7 +1086,7 @@ int ptrace_request(struct task_struct *child, long re= quest, else mask =3D &child->blocked; =20 - if (copy_to_user(datavp, mask, sizeof(sigset_t))) + if (copy_sigset_to_user(datavp, mask, sigsetsize)) ret =3D -EFAULT; else ret =3D 0; @@ -1095,16 +1096,11 @@ int ptrace_request(struct task_struct *child, long = request, =20 case PTRACE_SETSIGMASK: { sigset_t new_set; + size_t sigsetsize =3D (size_t) addr; =20 - if (addr !=3D sizeof(sigset_t)) { - ret =3D -EINVAL; - break; - } - - if (copy_from_user(&new_set, datavp, sizeof(sigset_t))) { - ret =3D -EFAULT; + ret =3D copy_sigset_from_user(&new_set, datavp, sigsetsize); + if (ret) break; - } =20 sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); =20 diff --git a/kernel/signal.c b/kernel/signal.c index 487bf4f5dadf..94b1828ae973 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -3091,13 +3091,14 @@ EXPORT_SYMBOL(sigprocmask); int set_user_sigmask(const sigset_t __user *umask, size_t sigsetsize) { sigset_t kmask; + int ret; =20 if (!umask) return 0; - if (sigsetsize !=3D sizeof(sigset_t)) - return -EINVAL; - if (copy_from_user(&kmask, umask, sizeof(sigset_t))) - return -EFAULT; + + ret =3D copy_sigset_from_user(&kmask, umask, sigsetsize); + if (ret) + return ret; =20 set_restore_sigmask(); current->saved_sigmask =3D current->blocked; @@ -3111,13 +3112,14 @@ int set_compat_user_sigmask(const compat_sigset_t _= _user *umask, size_t sigsetsize) { sigset_t kmask; + int ret; =20 if (!umask) return 0; - if (sigsetsize !=3D sizeof(compat_sigset_t)) - return -EINVAL; - if (get_compat_sigset(&kmask, umask)) - return -EFAULT; + + ret =3D copy_compat_sigset_from_user(&kmask, umask, sigsetsize); + if (ret) + return ret; =20 set_restore_sigmask(); current->saved_sigmask =3D current->blocked; @@ -3140,14 +3142,13 @@ SYSCALL_DEFINE4(rt_sigprocmask, int, how, sigset_t = __user *, nset, sigset_t old_set, new_set; int error; =20 - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize !=3D sizeof(sigset_t)) + if (!valid_sigsetsize(sigsetsize)) return -EINVAL; =20 old_set =3D current->blocked; =20 if (nset) { - if (copy_from_user(&new_set, nset, sizeof(sigset_t))) + if (copy_sigset_from_user(&new_set, nset, sigsetsize)) return -EFAULT; sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); =20 @@ -3157,7 +3158,7 @@ SYSCALL_DEFINE4(rt_sigprocmask, int, how, sigset_t __= user *, nset, } =20 if (oset) { - if (copy_to_user(oset, &old_set, sizeof(sigset_t))) + if (copy_sigset_to_user(oset, &old_set, sigsetsize)) return -EFAULT; } =20 @@ -3168,16 +3169,16 @@ SYSCALL_DEFINE4(rt_sigprocmask, int, how, sigset_t = __user *, nset, COMPAT_SYSCALL_DEFINE4(rt_sigprocmask, int, how, compat_sigset_t __user *,= nset, compat_sigset_t __user *, oset, compat_size_t, sigsetsize) { - sigset_t old_set =3D current->blocked; + sigset_t old_set, new_set; + int error; =20 - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize !=3D sizeof(sigset_t)) + if (!valid_sigsetsize(sigsetsize)) return -EINVAL; =20 + old_set =3D current->blocked; + if (nset) { - sigset_t new_set; - int error; - if (get_compat_sigset(&new_set, nset)) + if (copy_compat_sigset_from_user(&new_set, nset, sigsetsize)) return -EFAULT; sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); =20 @@ -3185,7 +3186,12 @@ COMPAT_SYSCALL_DEFINE4(rt_sigprocmask, int, how, com= pat_sigset_t __user *, nset, if (error) return error; } - return oset ? put_compat_sigset(oset, &old_set, sizeof(*oset)) : 0; + if (oset) { + if (copy_compat_sigset_to_user(oset, &old_set, sigsetsize)) + return -EFAULT; + } + + return 0; } #endif =20 @@ -3210,12 +3216,12 @@ SYSCALL_DEFINE2(rt_sigpending, sigset_t __user *, u= set, size_t, sigsetsize) { sigset_t set; =20 - if (sigsetsize > sizeof(*uset)) + if (!valid_sigsetsize(sigsetsize)) return -EINVAL; =20 do_sigpending(&set); =20 - if (copy_to_user(uset, &set, sigsetsize)) + if (copy_sigset_to_user(uset, &set, sigsetsize)) return -EFAULT; =20 return 0; @@ -3227,12 +3233,15 @@ COMPAT_SYSCALL_DEFINE2(rt_sigpending, compat_sigset= _t __user *, uset, { sigset_t set; =20 - if (sigsetsize > sizeof(*uset)) + if (!valid_sigsetsize(sigsetsize)) return -EINVAL; =20 do_sigpending(&set); =20 - return put_compat_sigset(uset, &set, sigsetsize); + if (copy_compat_sigset_to_user(uset, &set, sigsetsize)) + return -EFAULT; + + return 0; } #endif =20 @@ -3627,12 +3636,9 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __us= er *, uthese, kernel_siginfo_t info; int ret; =20 - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize !=3D sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&these, uthese, sizeof(these))) - return -EFAULT; + ret =3D copy_sigset_from_user(&these, uthese, sigsetsize); + if (ret) + return ret; =20 if (uts) { if (get_timespec64(&ts, uts)) @@ -3660,11 +3666,9 @@ SYSCALL_DEFINE4(rt_sigtimedwait_time32, const sigset= _t __user *, uthese, kernel_siginfo_t info; int ret; =20 - if (sigsetsize !=3D sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&these, uthese, sizeof(these))) - return -EFAULT; + ret =3D copy_sigset_from_user(&these, uthese, sigsetsize); + if (ret) + return ret; =20 if (uts) { if (get_old_timespec32(&ts, uts)) @@ -3692,11 +3696,9 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait_time64, compa= t_sigset_t __user *, uthese, kernel_siginfo_t info; long ret; =20 - if (sigsetsize !=3D sizeof(sigset_t)) - return -EINVAL; - - if (get_compat_sigset(&s, uthese)) - return -EFAULT; + ret =3D copy_compat_sigset_from_user(&s, uthese, sigsetsize); + if (ret) + return ret; =20 if (uts) { if (get_timespec64(&t, uts)) @@ -3723,11 +3725,9 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait_time32, compa= t_sigset_t __user *, uthese, kernel_siginfo_t info; long ret; =20 - if (sigsetsize !=3D sizeof(sigset_t)) - return -EINVAL; - - if (get_compat_sigset(&s, uthese)) - return -EFAULT; + ret =3D copy_compat_sigset_from_user(&s, uthese, sigsetsize); + if (ret) + return ret; =20 if (uts) { if (get_old_timespec32(&t, uts)) @@ -4370,21 +4370,36 @@ SYSCALL_DEFINE4(rt_sigaction, int, sig, size_t, sigsetsize) { struct k_sigaction new_sa, old_sa; + size_t sa_len =3D sizeof(struct sigaction) - sizeof(sigset_t); int ret; =20 - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize !=3D sizeof(sigset_t)) - return -EINVAL; + /* struct sigaction contains a sigset_t; handle cases where + * user and kernel sizes of sigset_t differ. + */ =20 - if (act && copy_from_user(&new_sa.sa, act, sizeof(new_sa.sa))) - return -EFAULT; + memset(&new_sa.sa, 0, sizeof(struct sigaction)); + + if (act) { + if (copy_from_user(&new_sa.sa, act, sa_len)) + return -EFAULT; + ret =3D copy_sigset_from_user(&new_sa.sa.sa_mask, &act->sa_mask, + sigsetsize); + if (ret) + return ret; + } =20 ret =3D do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL); if (ret) return ret; =20 - if (oact && copy_to_user(oact, &old_sa.sa, sizeof(old_sa.sa))) - return -EFAULT; + if (oact) { + if (copy_to_user(oact, &old_sa.sa, sa_len)) + return -EFAULT; + ret =3D copy_sigset_to_user(&oact->sa_mask, &old_sa.sa.sa_mask, + sigsetsize); + if (ret) + return ret; + } =20 return 0; } @@ -4400,8 +4415,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigaction, int, sig, #endif int ret; =20 - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize !=3D sizeof(compat_sigset_t)) + if (!valid_sigsetsize(sigsetsize)) return -EINVAL; =20 if (act) { @@ -4412,7 +4426,8 @@ COMPAT_SYSCALL_DEFINE4(rt_sigaction, int, sig, ret |=3D get_user(restorer, &act->sa_restorer); new_ka.sa.sa_restorer =3D compat_ptr(restorer); #endif - ret |=3D get_compat_sigset(&new_ka.sa.sa_mask, &act->sa_mask); + ret |=3D copy_compat_sigset_from_user(&new_ka.sa.sa_mask, + &act->sa_mask, sigsetsize); ret |=3D get_user(new_ka.sa.sa_flags, &act->sa_flags); if (ret) return -EFAULT; @@ -4422,8 +4437,8 @@ COMPAT_SYSCALL_DEFINE4(rt_sigaction, int, sig, if (!ret && oact) { ret =3D put_user(ptr_to_compat(old_ka.sa.sa_handler),=20 &oact->sa_handler); - ret |=3D put_compat_sigset(&oact->sa_mask, &old_ka.sa.sa_mask, - sizeof(oact->sa_mask)); + ret |=3D copy_compat_sigset_to_user(&oact->sa_mask, + &old_ka.sa.sa_mask, sigsetsize); ret |=3D put_user(old_ka.sa.sa_flags, &oact->sa_flags); #ifdef __ARCH_HAS_SA_RESTORER ret |=3D put_user(ptr_to_compat(old_ka.sa.sa_restorer), @@ -4590,13 +4605,11 @@ static int sigsuspend(sigset_t *set) SYSCALL_DEFINE2(rt_sigsuspend, sigset_t __user *, unewset, size_t, sigsets= ize) { sigset_t newset; + int ret; =20 - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize !=3D sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&newset, unewset, sizeof(newset))) - return -EFAULT; + ret =3D copy_sigset_from_user(&newset, unewset, sigsetsize); + if (ret) + return ret; return sigsuspend(&newset); } =20 @@ -4604,13 +4617,11 @@ SYSCALL_DEFINE2(rt_sigsuspend, sigset_t __user *, u= newset, size_t, sigsetsize) COMPAT_SYSCALL_DEFINE2(rt_sigsuspend, compat_sigset_t __user *, unewset, c= ompat_size_t, sigsetsize) { sigset_t newset; + int ret; =20 - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize !=3D sizeof(sigset_t)) - return -EINVAL; - - if (get_compat_sigset(&newset, unewset)) - return -EFAULT; + ret =3D copy_compat_sigset_from_user(&newset, unewset, sigsetsize); + if (ret) + return ret; return sigsuspend(&newset); } #endif diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 7851f3a1b5f7..c8b3645c9a7d 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -3891,8 +3891,10 @@ static long kvm_vcpu_ioctl(struct file *filp, if (copy_from_user(&kvm_sigmask, argp, sizeof(kvm_sigmask))) goto out; - r =3D -EINVAL; - if (kvm_sigmask.len !=3D sizeof(sigset)) + r =3D copy_sigset_from_user(&sigset, + (sigset_t __user *) &sigmask_arg->sigset, + kvm_sigmask.len); + if (r) goto out; r =3D -EFAULT; if (copy_from_user(&sigset, sigmask_arg->sigset, @@ -3963,12 +3965,10 @@ static long kvm_vcpu_compat_ioctl(struct file *filp, if (copy_from_user(&kvm_sigmask, argp, sizeof(kvm_sigmask))) goto out; - r =3D -EINVAL; - if (kvm_sigmask.len !=3D sizeof(compat_sigset_t)) - goto out; - r =3D -EFAULT; - if (get_compat_sigset(&sigset, - (compat_sigset_t __user *)sigmask_arg->sigset)) + r =3D copy_compat_sigset_from_user(&sigset, + (compat_sigset_t __user *) &sigmask_arg->sigset, + kvm_sigmask.len); + if (r) goto out; r =3D kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset); } else --=20 2.30.2 From nobody Wed Jul 1 03:09:27 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 20BA2C433EF for ; Mon, 3 Jan 2022 18:35:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235703AbiACSfW (ORCPT ); Mon, 3 Jan 2022 13:35:22 -0500 Received: from drummond.us ([74.95.14.229]:40377 "EHLO talisker.home.drummond.us" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235705AbiACSfS (ORCPT ); Mon, 3 Jan 2022 13:35:18 -0500 X-Greylist: delayed 875 seconds by postgrey-1.27 at vger.kernel.org; Mon, 03 Jan 2022 13:35:12 EST Received: from talisker.home.drummond.us (localhost [127.0.0.1]) by talisker.home.drummond.us (8.15.2/8.15.2/Debian-20) with ESMTP id 203IKWnj983506; Mon, 3 Jan 2022 10:20:32 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=home.drummond.us; s=default; t=1641234033; bh=f6bKazr4Vyn0DnvfqZzgyhTykMFxWyhjSEgJ0jCBDjQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Z4lMRRX8BRd9RmxIQ54Y0iCgerITrvWRZ0kWwIW5uwIYNkFVwOzawIdpalrZ6VEAf 5tZUMrYbcFa+8X3iJQ3BgeVx9IW7EZnuaIa89s0YfvVoy2zH1ePVhdPKYi+RT2BVsL ljGqmYDki79peMJknxxH52oHdir1BVJJdLUSpJTsW1uXaKa2yDi2kHNl8olhisFSIT AYPW9bmNWNSbUgtQ4aAUAchkKtVp5DIkO/sNoVrGNs87A37VDvR4A96YjYvaex9YAO ftdTrGE2WqM4nrQPzKLN3yKXvPXugWew4M3CceUKmj7ImLWfUSE9tZXrsM7I1czP0l u6KO95Ig//NkA== Received: (from walt@localhost) by talisker.home.drummond.us (8.15.2/8.15.2/Submit) id 203IKWSg983505; Mon, 3 Jan 2022 10:20:32 -0800 From: Walt Drummond To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" Cc: linux-kernel@vger.kernel.org, Walt Drummond Subject: [RFC PATCH 2/8] signals: Put the full signal mask on the signal stack for x86_64, X32 and ia32 compatibility mode Date: Mon, 3 Jan 2022 10:19:50 -0800 Message-Id: <20220103181956.983342-3-walt@drummond.us> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220103181956.983342-1-walt@drummond.us> References: <20220103181956.983342-1-walt@drummond.us> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Put the complete sigset_t in the real-tme signal stack frame for x86_64, x32 and ia32 compatibility mode on x86. Signed-off-by: Walt Drummond --- arch/x86/ia32/ia32_signal.c | 5 +++-- arch/x86/include/asm/sighandling.h | 34 ++++++++++++++++++++++++++++++ arch/x86/kernel/signal.c | 11 +++------- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index 5e3d9b7fd5fb..03a0ecd8c7f3 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -130,7 +130,8 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn) =20 if (!access_ok(frame, sizeof(*frame))) goto badframe; - if (__get_user(set.sig[0], (__u64 __user *)&frame->uc.uc_sigmask)) + if (copy_from_user(&set, &frame->uc.uc_sigmask, + sizeof(frame->uc.uc_sigmask))) goto badframe; =20 set_current_blocked(&set); @@ -347,7 +348,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig, */ unsafe_put_user(*((u64 *)&code), (u64 __user *)frame->retcode, Efault); unsafe_put_sigcontext32(&frame->uc.uc_mcontext, fp, regs, set, Efault); - unsafe_put_user(*(__u64 *)set, (__u64 __user *)&frame->uc.uc_sigmask, Efa= ult); + unsafe_put_compat_sigmask(set, frame, Efault); user_access_end(); =20 if (__copy_siginfo_to_user32(&frame->info, &ksig->info)) diff --git a/arch/x86/include/asm/sighandling.h b/arch/x86/include/asm/sigh= andling.h index 65e667279e0f..e247bea06a17 100644 --- a/arch/x86/include/asm/sighandling.h +++ b/arch/x86/include/asm/sighandling.h @@ -15,4 +15,38 @@ =20 void signal_fault(struct pt_regs *regs, void __user *frame, char *where); =20 +static inline int +__unsafe_put_sigmask(char *set, char __user *fp, size_t size) +{ + char *src; + char __user *dst; + size_t len; + + len =3D size; + src =3D set; + dst =3D fp; + unsafe_copy_loop(dst, src, len, unsigned long, Efault); + + return 0; +Efault: + return -EFAULT; +} + +#define unsafe_put_sigmask(set, frame, label) \ +do { \ + if (__unsafe_put_sigmask((char *) set, \ + (char __user *) &(frame)->uc.uc_sigmask, \ + sizeof(sigset_t))) \ + goto label; \ +} while (0) + +#define unsafe_put_compat_sigmask(set, frame, label) \ +do { \ + if (__unsafe_put_sigmask((char *) set, \ + (char __user *) &(frame)->uc.uc_sigmask, \ + sizeof(compat_sigset_t))) \ + goto label; \ +} while (0) + + #endif /* _ASM_X86_SIGHANDLING_H */ diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index f4d21e470083..bb5f3f39c412 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -203,11 +203,6 @@ do { \ goto label; \ } while(0); =20 -#define unsafe_put_sigmask(set, frame, label) \ - unsafe_put_user(*(__u64 *)(set), \ - (__u64 __user *)&(frame)->uc.uc_sigmask, \ - label) - /* * Set up a signal frame. */ @@ -587,7 +582,7 @@ static int x32_setup_rt_frame(struct ksignal *ksig, restorer =3D ksig->ka.sa.sa_restorer; unsafe_put_user(restorer, (unsigned long __user *)&frame->pretcode, Efaul= t); unsafe_put_sigcontext(&frame->uc.uc_mcontext, fp, regs, set, Efault); - unsafe_put_sigmask(set, frame, Efault); + unsafe_put_compat_sigmask(set, frame, Efault); user_access_end(); =20 if (ksig->ka.sa.sa_flags & SA_SIGINFO) { @@ -664,7 +659,7 @@ SYSCALL_DEFINE0(rt_sigreturn) frame =3D (struct rt_sigframe __user *)(regs->sp - sizeof(long)); if (!access_ok(frame, sizeof(*frame))) goto badframe; - if (__get_user(*(__u64 *)&set, (__u64 __user *)&frame->uc.uc_sigmask)) + if (copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(sigset_t))) goto badframe; if (__get_user(uc_flags, &frame->uc.uc_flags)) goto badframe; @@ -922,7 +917,7 @@ COMPAT_SYSCALL_DEFINE0(x32_rt_sigreturn) =20 if (!access_ok(frame, sizeof(*frame))) goto badframe; - if (__get_user(set.sig[0], (__u64 __user *)&frame->uc.uc_sigmask)) + if (copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(compat_sigset_t))) goto badframe; if (__get_user(uc_flags, &frame->uc.uc_flags)) goto badframe; --=20 2.30.2 From nobody Wed Jul 1 03:09:27 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6DC1AC433F5 for ; Mon, 3 Jan 2022 18:35:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235753AbiACSfD (ORCPT ); Mon, 3 Jan 2022 13:35:03 -0500 Received: from drummond.us ([74.95.14.229]:40377 "EHLO talisker.home.drummond.us" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235740AbiACSfA (ORCPT ); Mon, 3 Jan 2022 13:35:00 -0500 X-Greylist: delayed 836 seconds by postgrey-1.27 at vger.kernel.org; Mon, 03 Jan 2022 13:34:55 EST Received: from talisker.home.drummond.us (localhost [127.0.0.1]) by talisker.home.drummond.us (8.15.2/8.15.2/Debian-20) with ESMTP id 203IKXWJ983520; Mon, 3 Jan 2022 10:20:33 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=home.drummond.us; s=default; t=1641234033; bh=cfkDVUC04N1/5TKLzChdaVzjxjk6gzgwbrbQoSLvShw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=3bO7fBxepM4+/51f0L5qyw/bOgsjQRd0fcDGjKx7c40y65UfrwqkoWMcaCES5BrN+ nKUb6uagsnHUTHJSULqwvRKsCgqW8BQWZINOK9KZcOlVzVOOcxk9pax4Xeml/9DZvT 0x29XgMTtXonYouglW8+Jearv13ejCZnKViYIIzsICH7kNq1p/nA+R+VO/fleXM9jM NLDHVByAShijXnZLRxOBLlC4QnB/7SJBCrgGxHWHjkv2liiZMYy0VVqqqEINsP+j34 gyu9RYX96ayZW6dsA+FKzRMPlkU/qOGHtc9saAcEGyQonMqzGiG/z4oHRqhE1bbP0H CEKRA26oxA4nw== Received: (from walt@localhost) by talisker.home.drummond.us (8.15.2/8.15.2/Submit) id 203IKXpq983519; Mon, 3 Jan 2022 10:20:33 -0800 From: Walt Drummond To: Thomas Gleixner , John Johansen , James Morris , "Serge E. Hallyn" Cc: linux-kernel@vger.kernel.org, Walt Drummond , linux-security-module@vger.kernel.org Subject: [RFC PATCH 3/8] signals: Use a helper function to test if a signal is a real-time signal. Date: Mon, 3 Jan 2022 10:19:51 -0800 Message-Id: <20220103181956.983342-4-walt@drummond.us> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220103181956.983342-1-walt@drummond.us> References: <20220103181956.983342-1-walt@drummond.us> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Rather than testing against SIGRTMIN/SIGRTMAX directly, use this helper to determine if a signal is a real-time signal. Signed-off-by: Walt Drummond --- include/linux/signal.h | 8 ++++++++ kernel/signal.c | 6 +++--- kernel/time/posix-timers.c | 3 ++- security/apparmor/ipc.c | 4 ++-- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/linux/signal.h b/include/linux/signal.h index c66d4f520228..a730f3d4615e 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -53,6 +53,14 @@ enum siginfo_layout { =20 enum siginfo_layout siginfo_layout(unsigned sig, int si_code); =20 +/* Test if 'sig' is a realtime signal. Use this instead of testing + * SIGRTMIN/SIGRTMAX directly. + */ +static inline int realtime_signal(unsigned long sig) +{ + return (sig >=3D SIGRTMIN) && (sig <=3D SIGRTMAX); +} + /* * Define some primitives to manipulate sigset_t. */ diff --git a/kernel/signal.c b/kernel/signal.c index 94b1828ae973..a2f0e38ba934 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1065,7 +1065,7 @@ static void complete_signal(int sig, struct task_stru= ct *p, enum pid_type type) =20 static inline bool legacy_queue(struct sigpending *signals, int sig) { - return (sig < SIGRTMIN) && sigismember(&signals->signal, sig); + return !realtime_signal(sig) && sigismember(&signals->signal, sig); } =20 static int __send_signal(int sig, struct kernel_siginfo *info, struct task= _struct *t, @@ -1108,7 +1108,7 @@ static int __send_signal(int sig, struct kernel_sigin= fo *info, struct task_struc * make sure at least one signal gets delivered and don't * pass on the info struct. */ - if (sig < SIGRTMIN) + if (!realtime_signal(sig)) override_rlimit =3D (is_si_special(info) || info->si_code >=3D 0); else override_rlimit =3D 0; @@ -1144,7 +1144,7 @@ static int __send_signal(int sig, struct kernel_sigin= fo *info, struct task_struc break; } } else if (!is_si_special(info) && - sig >=3D SIGRTMIN && info->si_code !=3D SI_USER) { + realtime_signal(sig) && info->si_code !=3D SI_USER) { /* * Queue overflow, abort. We may abort if the * signal was rt and sent by user using something diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 1cd10b102c51..6afb98eadd1d 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -442,7 +442,8 @@ static struct pid *good_sigevent(sigevent_t * event) fallthrough; case SIGEV_SIGNAL: case SIGEV_THREAD: - if (event->sigev_signo <=3D 0 || event->sigev_signo > SIGRTMAX) + /* Signal 0 is a valid signal, just not here. */ + if (!valid_signal(event->sigev_signo) || event->sigev_signo =3D=3D 0) return NULL; fallthrough; case SIGEV_NONE: diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index fe36d112aad9..8149b989b665 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -130,9 +130,9 @@ int aa_may_ptrace(struct aa_label *tracer, struct aa_la= bel *tracee, =20 static inline int map_signal_num(int sig) { - if (sig > SIGRTMAX) + if (!valid_signal(sig)) return SIGUNKNOWN; - else if (sig >=3D SIGRTMIN) + else if (realtime_signal(sig)) return sig - SIGRTMIN + SIGRT_BASE; else if (sig < MAXMAPPED_SIG) return sig_map[sig]; --=20 2.30.2 From nobody Wed Jul 1 03:09:27 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B72B1C433EF for ; Mon, 3 Jan 2022 18:35:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235810AbiACSfn (ORCPT ); Mon, 3 Jan 2022 13:35:43 -0500 Received: from drummond.us ([74.95.14.229]:40377 "EHLO talisker.home.drummond.us" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235794AbiACSff (ORCPT ); Mon, 3 Jan 2022 13:35:35 -0500 X-Greylist: delayed 810 seconds by postgrey-1.27 at vger.kernel.org; Mon, 03 Jan 2022 13:35:34 EST Received: from talisker.home.drummond.us (localhost [127.0.0.1]) by talisker.home.drummond.us (8.15.2/8.15.2/Debian-20) with ESMTP id 203IKZSZ983534; Mon, 3 Jan 2022 10:20:35 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=home.drummond.us; s=default; t=1641234035; bh=1S4aZEe8E5gnTI2K70dnsEWUGccc1BInmbt849S/duM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WyQCq7DasK4r7khY1NLSZ2054ipNjjssFr3IyHOfjRw5AwqYZ2h1rMu3x89S23nM3 Ijrf2PSNrKMtHbvM1QVI0uQzA9fHwSQnaNVo9c695mnTtZ5QkdJOh8dsfSfVr/vxdb JGzGBT4ajjhJjmYk3jiziZi3ZT/9Lr6ojWfoe4avw5LmxSc9jiAfQs6VbMmEehFDSS 8LTfFzcx4UeVso+E9qMwpmobvxkvHR/4mx9ZLg2awfdMp7VC6a97ArXtTqHOHQZ3jw h5U7DJULvrNd5I4BNEH6jJj88fnGmh+esyJd+r02P1ve4B/RMSGezj7mpD+bfbX1ah SqWcHVc1YVwQA== Received: (from walt@localhost) by talisker.home.drummond.us (8.15.2/8.15.2/Submit) id 203IKZXV983533; Mon, 3 Jan 2022 10:20:35 -0800 From: Walt Drummond To: Richard Henderson , Ivan Kokshaysky , Matt Turner , Geert Uytterhoeven , Dinh Nguyen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Adaptec OEM Raid Solutions , "James E.J. Bottomley" , "Martin K. Petersen" , Jeff Layton , Ilya Dryomov , David Woodhouse , Richard Weinberger , Trond Myklebust , Anna Schumaker , "J. Bruce Fields" , Chuck Lever , Alexander Viro , Oleg Nesterov , Paolo Bonzini Cc: linux-kernel@vger.kernel.org, Walt Drummond , linux-alpha@vger.kernel.org, linux-m68k@vger.kernel.org, linux-scsi@vger.kernel.org, ceph-devel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-nfs@vger.kernel.org, linux-fsdevel@vger.kernel.org, kvm@vger.kernel.org Subject: [RFC PATCH 4/8] signals: Remove sigmask() macro Date: Mon, 3 Jan 2022 10:19:52 -0800 Message-Id: <20220103181956.983342-5-walt@drummond.us> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220103181956.983342-1-walt@drummond.us> References: <20220103181956.983342-1-walt@drummond.us> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" 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 --- 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 @@ =20 #define DEBUG_SIG 0 =20 -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) +#define _BLOCKABLE (~(compat_sigmask(SIGKILL) | compat_sigmask(SIGSTOP))) =20 asmlinkage void ret_from_sys_call(void); =20 @@ -47,7 +47,7 @@ SYSCALL_DEFINE2(osf_sigprocmask, int, how, unsigned long,= newmask) sigset_t mask; unsigned long res; =20 - siginitset(&mask, newmask & _BLOCKABLE); + compat_siginitset(&mask, newmask & _BLOCKABLE); res =3D 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 =20 -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"); } =20 -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 _s= ig) return ret; } =20 -#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 #include =20 -#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; =20 #define __HAVE_ARCH_SIG_BITOPS =20 -#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] |=3D 1 << (sig % _NSIG_BPW); } =20 -#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 _s= ig) return ret; } =20 -#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) =20 -#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 =3D { static void ceph_block_sigs(sigset_t *oldset) { sigset_t mask; - siginitsetinv(&mask, sigmask(SIGKILL)); + siginitsetinv(&mask, SIGKILL); sigprocmask(SIG_BLOCK, &mask, oldset); } =20 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 =3D _c; sigset_t hupmask; =20 - 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 @@ =20 #define NLMDBG_FACILITY NLMDBG_SVC #define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE) -#define ALLOWED_SIGS (sigmask(SIGKILL)) =20 static struct svc_program nlmsvc_program; =20 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 fl= ags) if (flags & ~(SFD_CLOEXEC | SFD_NONBLOCK)) return -EINVAL; =20 - sigdelsetmask(mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); + sigdelset(mask, SIGKILL, SIGSTOP); signotset(mask); =20 if (ufd =3D=3D -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 { =20 enum siginfo_layout siginfo_layout(unsigned sig, int si_code); =20 +/* Test if 'sig' is valid signal. Use this instead of testing _NSIG direct= ly */ +static inline int valid_signal(unsigned long sig) +{ + return sig <=3D _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) } =20 /* - * 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) */ =20 #ifndef __HAVE_ARCH_SIG_BITOPS -#include +#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 =20 /* We don't use 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 =3D _sig - 1; if (_NSIG_WORDS =3D=3D 1) @@ -79,7 +90,7 @@ static inline void sigaddset(sigset_t *set, int _sig) set->sig[sig / _NSIG_BPW] |=3D 1UL << (sig % _NSIG_BPW); } =20 -static inline void sigdelset(sigset_t *set, int _sig) +static inline void __sigset_del(sigset_t *set, int _sig) { unsigned long sig =3D _sig - 1; if (_NSIG_WORDS =3D=3D 1) @@ -88,33 +99,72 @@ static inline void sigdelset(sigset_t *set, int _sig) set->sig[sig / _NSIG_BPW] &=3D ~(1UL << (sig % _NSIG_BPW)); } =20 -static inline int sigismember(sigset_t *set, int _sig) +static inline int __sigset_ismember(sigset_t *set, int _sig) { unsigned long sig =3D _sig - 1; if (_NSIG_WORDS =3D=3D 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)); } =20 -#endif /* __HAVE_ARCH_SIG_BITOPS */ +/* Some primitives for setting/deleting signals from sigset_t. Use these.= */ =20 -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]) =3D=3D 0; - case 2: - return (set->sig[1] | set->sig[0]) =3D=3D 0; - case 1: - return set->sig[0] =3D=3D 0; - default: - BUILD_BUG(); - return 0; + va_list ap; + int sig; + + va_start(ap, count); + while (count > 0) { + sig =3D va_arg(ap, int); + if (valid_signal(sig) && sig !=3D 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 =3D va_arg(ap, int); + if (valid_signal(sig) && sig !=3D 0) + sigset_add(set, sig); + count--; + } + va_end(ap); +} + +static inline int sigismember(sigset_t *set, int sig) +{ + if (!valid_signal(sig) || sig =3D=3D 0) + return 0; + return sigset_ismember(set, sig); } =20 +#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] =3D=3D set2->sig[0]); case 1: return set1->sig[0] =3D=3D set2->sig[0]; + default: + return memcmp(set1, set2, sizeof(sigset_t)) =3D=3D 0; } return 0; } =20 -#define sigmask(sig) (1UL << ((sig) - 1)) +static inline int sigisemptyset(sigset_t *set) +{ + sigset_t empty =3D {0}; + + return sigequalsets(set, &empty); +} =20 #ifndef __HAVE_ARCH_SIG_SETOPS #include @@ -141,6 +198,7 @@ static inline int sigequalsets(const sigset_t *set1, co= nst 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] =3D op(a0, b0); \ break; \ default: \ - BUILD_BUG(); \ + for (i =3D 0; i < _NSIG_WORDS; i++) \ + r->sig[i] =3D op(a->sig[i], b->sig[i]); \ + break; \ } \ } =20 @@ -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] =3D op(set->sig[3]); \ set->sig[2] =3D op(set->sig[2]); \ @@ -188,7 +250,9 @@ static inline void name(sigset_t *set) \ case 1: set->sig[0] =3D op(set->sig[0]); \ break; \ default: \ - BUILD_BUG(); \ + for (i =3D 0; i < _NSIG_WORDS; i++) \ + set->sig[i] =3D op(set->sig[i]); \ + break; \ } \ } =20 @@ -224,24 +288,13 @@ static inline void sigfillset(sigset_t *set) } } =20 -/* Some extensions for manipulating the low 32 signals in particular. */ +#endif /* __HAVE_ARCH_SIG_SETOPS */ =20 -static inline void sigaddsetmask(sigset_t *set, unsigned long mask) -{ - set->sig[0] |=3D mask; -} +/* Primitives for handing the compat (first long) sigset_t */ =20 -static inline void sigdelsetmask(sigset_t *set, unsigned long mask) -{ - set->sig[0] &=3D ~mask; -} +#define compat_sigmask(sig) (1UL << ((sig) - 1)) =20 -static inline int sigtestsetmask(sigset_t *set, unsigned long mask) -{ - return (set->sig[0] & mask) !=3D 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] =3D mask; switch (_NSIG_WORDS) { @@ -254,7 +307,7 @@ static inline void siginitset(sigset_t *set, unsigned l= ong mask) } } =20 -static inline void siginitsetinv(sigset_t *set, unsigned long mask) +static inline void compat_siginitsetinv(sigset_t *set, unsigned long mask) { set->sig[0] =3D ~mask; switch (_NSIG_WORDS) { @@ -267,7 +320,21 @@ static inline void siginitsetinv(sigset_t *set, unsign= ed long mask) } } =20 -#endif /* __HAVE_ARCH_SIG_SETOPS */ +static inline void compat_sigaddsetmask(sigset_t *set, unsigned long mask) +{ + set->sig[0] |=3D mask; +} + +static inline void compat_sigdelsetmask(sigset_t *set, unsigned long mask) +{ + set->sig[0] &=3D ~mask; +} + +static inline int compat_sigtestsetmask(sigset_t *set, unsigned long mask) +{ + return (set->sig[0] & mask) !=3D 0; +} + =20 /* 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) =20 extern void flush_sigqueue(struct sigpending *queue); =20 -/* Test if 'sig' is valid signal. Use this instead of testing _NSIG direct= ly */ -static inline int valid_signal(unsigned long sig) -{ - return sig <=3D _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. */ =20 +static inline int sig_kernel_stop(unsigned long sig) +{ + return sig =3D=3D SIGSTOP || + sig =3D=3D SIGTSTP || + sig =3D=3D SIGTTIN || + sig =3D=3D SIGTTOU; +} + +static inline int sig_kernel_ignore(unsigned long sig) +{ + return sig =3D=3D SIGCONT || + sig =3D=3D SIGCHLD || + sig =3D=3D SIGWINCH || + sig =3D=3D SIGURG; +} + +static inline int sig_kernel_only(unsigned long sig) +{ + return sig =3D=3D SIGKILL || + sig =3D=3D SIGSTOP; +} + +static inline int sig_kernel_coredump(unsigned long sig) +{ + return sig =3D=3D SIGQUIT || + sig =3D=3D SIGILL || + sig =3D=3D SIGTRAP || + sig =3D=3D SIGABRT || + sig =3D=3D SIGFPE || + sig =3D=3D SIGSEGV || + sig =3D=3D SIGBUS || + sig =3D=3D SIGSYS || + sig =3D=3D SIGXCPU || #ifdef SIGEMT -#define SIGEMT_MASK rt_sigmask(SIGEMT) -#else -#define SIGEMT_MASK 0 + sig =3D=3D SIGEMT || #endif + sig =3D=3D SIGXFSZ; +} =20 -#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 =3D=3D SIGILL || + sig =3D=3D SIGFPE || + sig =3D=3D SIGSEGV || + sig =3D=3D SIGBUS || + sig =3D=3D SIGTRAP || + sig =3D=3D SIGCHLD || + sig =3D=3D SIGPOLL || +#ifdef SIGEMT + sig =3D=3D SIGEMT || #endif + sig =3D=3D SIGSYS; +} =20 -#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 =3D=3D SIGSEGV || + sig =3D=3D SIGBUS || + sig =3D=3D SIGILL || + sig =3D=3D SIGTRAP || + sig =3D=3D SIGFPE || + sig =3D=3D SIGSYS; +} =20 #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 =3D=3D SIG_DFL) =20 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 &=3D ~(sigmask(SIGKILL) | sigmask(SIGSTOP)); + new_set &=3D ~(compat_sigmask(SIGKILL) | compat_sigmask(SIGSTOP)); =20 new_blocked =3D current->blocked; =20 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_proc= ess( * fatal or STOP */ p->flags |=3D PF_IO_WORKER; - siginitsetinv(&p->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP)); + siginitsetinv(&p->blocked, SIGKILL, SIGSTOP); } =20 /* 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 re= quest, if (ret) break; =20 - sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); + sigdelset(&new_set, SIGKILL, SIGSTOP); =20 /* * 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; =20 int print_fatal_signals __read_mostly; =20 +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) } =20 /* 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 =3D 0; + int i, sig; + sigset_t pend, s; =20 - s =3D pending->signal.sig; - m =3D mask->sig; + sigandnsets(&pend, &pending->signal, mask); =20 - /* - * Handle the first word specially: it contains the - * synchronous signals that need to be dequeued first. - */ - x =3D *s &~ *m; - if (x) { - if (x & SYNCHRONOUS_MASK) - x &=3D SYNCHRONOUS_MASK; - sig =3D ffz(~x) + 1; - return sig; - } + /* Handle synchronous signals first */ + sigandsets(&s, &pend, &signal_synchronous_mask); + if (!sigisemptyset(&s)) + pend =3D s; =20 - switch (_NSIG_WORDS) { - default: - for (i =3D 1; i < _NSIG_WORDS; ++i) { - x =3D *++s &~ *++m; - if (!x) - continue; - sig =3D ffz(~x) + i*_NSIG_BPW + 1; - break; + for (i =3D 0; i < _NSIG_WORDS; i++) { + if (pend.sig[i] !=3D 0) { + sig =3D ffz(~pend.sig[i]) + i*_NSIG_BPW + 1; + return sig; } - break; - - case 2: - x =3D s[1] &~ m[1]; - if (!x) - break; - sig =3D ffz(~x) + _NSIG_BPW + 1; - break; - - case 1: - /* Nothing to do */ - break; } =20 - return sig; + return 0; } =20 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 =3D current; struct sigpending *pending =3D &tsk->pending; struct sigqueue *q, *sync =3D NULL; + sigset_t s; =20 /* * 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; =20 /* @@ -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 =3D q; goto next; } @@ -795,6 +772,25 @@ static void flush_sigqueue_mask(sigset_t *mask, struct= sigpending *s) } } =20 +#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 =3D va_arg(ap, int); + if (valid_signal(sig) && sig !=3D 0) + sigset_add(&mask, sig); + count--; + } + flush_sigqueue_mask(&mask, s); +} + static inline int is_si_special(const struct kernel_siginfo *info) { return info <=3D 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 =3D=3D 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_sigin= fo *info, struct task_struc sigset_t *signal =3D &delayed->signal; /* Can't queue both a stop and a continue signal */ if (sig =3D=3D 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 *ts= k, 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); } =20 @@ -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); =20 error =3D sigprocmask(how, &new_set, NULL); if (error) @@ -3180,7 +3174,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigprocmask, int, how, comp= at_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); =20 error =3D sigprocmask(how, &new_set, NULL); if (error) @@ -3586,7 +3580,7 @@ static int do_sigtimedwait(const sigset_t *which, ker= nel_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); =20 spin_lock_irq(&tsk->sighand->siglock); @@ -4111,8 +4105,7 @@ int do_sigaction(int sig, struct k_sigaction *act, st= ruct k_sigaction *oact) sigaction_compat_abi(act, oact); =20 if (act) { - sigdelsetmask(&act->sa.sa_mask, - sigmask(SIGKILL) | sigmask(SIGSTOP)); + sigdelset(&act->sa.sa_mask, SIGKILL, SIGSTOP); *k =3D *act; /* * POSIX 3.3.1.3: @@ -4126,9 +4119,7 @@ int do_sigaction(int sig, struct k_sigaction *act, st= ruct 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, =20 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] =3D new_set; @@ -4724,6 +4715,10 @@ void __init signals_init(void) { siginfo_buildtime_checks(); =20 + sigaddset(&signal_stop_mask, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU); + sigaddset(&signal_synchronous_mask, SIGSEGV, SIGBUS, SIGILL, SIGTRAP, + SIGFPE, SIGSYS); + sigqueue_cachep =3D KMEM_CACHE(sigqueue, SLAB_PANIC | SLAB_ACCOUNT); } =20 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 *sig= set) { if (sigset) { - sigdelsetmask(sigset, sigmask(SIGKILL)|sigmask(SIGSTOP)); + sigdelset(sigset, SIGKILL, SIGSTOP); vcpu->sigset_active =3D 1; vcpu->sigset =3D *sigset; } else --=20 2.30.2 From nobody Wed Jul 1 03:09:27 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 04291C433FE for ; Mon, 3 Jan 2022 18:34:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235656AbiACSex (ORCPT ); Mon, 3 Jan 2022 13:34:53 -0500 Received: from drummond.us ([74.95.14.229]:40377 "EHLO talisker.home.drummond.us" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S229728AbiACSew (ORCPT ); Mon, 3 Jan 2022 13:34:52 -0500 X-Greylist: delayed 855 seconds by postgrey-1.27 at vger.kernel.org; Mon, 03 Jan 2022 13:34:52 EST Received: from talisker.home.drummond.us (localhost [127.0.0.1]) by talisker.home.drummond.us (8.15.2/8.15.2/Debian-20) with ESMTP id 203IKaKh983549; Mon, 3 Jan 2022 10:20:36 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=home.drummond.us; s=default; t=1641234036; bh=tcvbk+9VbbAZwyAhc2AeyqHOfFE/HG33YA2bGuUxl2o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=H85IFCpE7rk1qXyLi3eaoYaNJR1MoGL/vqGeRkPGhH9BwaQmH+6ASvagbGKVUTtOq J8FxaTD1KLLDOj0konlyRv5x5se+kqTKCQOOIyp1KFgJRk15Tmt8XvIKsM2VzNShuQ wqoc6oz5SbWarhxqj/m5XRmIRB4oy+xGciUkCMXiieWlmWKFlP4/JRLhRN+gBLyP7Q 35xsO/Nnw0BwCXQ9jGk7sQxrRPkrIUPsmwzFgE9QCraMavcxiS8unaK2YZyM92Gryr GxgvW5KAPSlPjKY+ceWlY3fpsIHIIV36rFYl9hvo+VL0JZmfFU/CAvtXaSJKqqg7aT ua5nH2t0MxLcQ== Received: (from walt@localhost) by talisker.home.drummond.us (8.15.2/8.15.2/Submit) id 203IKa5I983548; Mon, 3 Jan 2022 10:20:36 -0800 From: Walt Drummond Cc: linux-kernel@vger.kernel.org, Walt Drummond , linux-fsdevel@vger.kernel.org Subject: [RFC PATCH 5/8] signals: Better support cases where _NSIG_WORDS is greater than 2 Date: Mon, 3 Jan 2022 10:19:53 -0800 Message-Id: <20220103181956.983342-6-walt@drummond.us> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220103181956.983342-1-walt@drummond.us> References: <20220103181956.983342-1-walt@drummond.us> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable To: unlisted-recipients:; (no To-header on input) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Directly handle the now more common cases where _NSIG_WORDS could be 3 or 4. Signed-off-by: Walt Drummond --- fs/proc/array.c | 3 +- include/linux/signal.h | 74 +++++++++++++++++++++++++++--------------- kernel/signal.c | 5 +++ 3 files changed, 55 insertions(+), 27 deletions(-) diff --git a/fs/proc/array.c b/fs/proc/array.c index 49be8c8ef555..f37c03077b58 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -223,7 +223,8 @@ void render_sigset_t(struct seq_file *m, const char *he= ader, =20 seq_puts(m, header); =20 - i =3D _NSIG; + /* Round up when _NSIG isn't a multiple of 4 */ + i =3D (_NSIG + 3) & ~0x03; do { int x =3D 0; =20 diff --git a/include/linux/signal.h b/include/linux/signal.h index eaf7991fffee..4084b765a6cc 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -168,18 +168,22 @@ do { \ static inline int sigequalsets(const sigset_t *set1, const sigset_t *set2) { switch (_NSIG_WORDS) { + default: + return memcmp(set1, set2, sizeof(sigset_t)) =3D=3D 0; case 4: return (set1->sig[3] =3D=3D set2->sig[3]) && (set1->sig[2] =3D=3D set2->sig[2]) && (set1->sig[1] =3D=3D set2->sig[1]) && (set1->sig[0] =3D=3D set2->sig[0]); + case 3: + return (set1->sig[2] =3D=3D set2->sig[2]) && + (set1->sig[1] =3D=3D set2->sig[1]) && + (set1->sig[0] =3D=3D set2->sig[0]); case 2: return (set1->sig[1] =3D=3D set2->sig[1]) && (set1->sig[0] =3D=3D set2->sig[0]); case 1: return set1->sig[0] =3D=3D set2->sig[0]; - default: - return memcmp(set1, set2, sizeof(sigset_t)) =3D=3D 0; } return 0; } @@ -197,27 +201,24 @@ static inline int sigisemptyset(sigset_t *set) #define _SIG_SET_BINOP(name, op) \ 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) { \ + default: \ + for (i =3D 0; i < _NSIG_WORDS; i++) \ + r->sig[i] =3D op(a->sig[i], b->sig[i]); \ + break; \ case 4: \ - a3 =3D a->sig[3]; a2 =3D a->sig[2]; \ - b3 =3D b->sig[3]; b2 =3D b->sig[2]; \ - r->sig[3] =3D op(a3, b3); \ - r->sig[2] =3D op(a2, b2); \ + r->sig[3] =3D op(a->sig[3], b->sig[3]); \ + fallthrough; \ + case 3: \ + r->sig[2] =3D op(a->sig[2], b->sig[2]); \ fallthrough; \ case 2: \ - a1 =3D a->sig[1]; b1 =3D b->sig[1]; \ - r->sig[1] =3D op(a1, b1); \ + r->sig[1] =3D op(a->sig[1], b->sig[1]); \ fallthrough; \ case 1: \ - a0 =3D a->sig[0]; b0 =3D b->sig[0]; \ - r->sig[0] =3D op(a0, b0); \ - break; \ - default: \ - for (i =3D 0; i < _NSIG_WORDS; i++) \ - r->sig[i] =3D op(a->sig[i], b->sig[i]); \ + r->sig[0] =3D op(a->sig[0], b->sig[0]); \ break; \ } \ } @@ -242,17 +243,22 @@ static inline void name(sigset_t *set) \ int i; \ \ switch (_NSIG_WORDS) { \ - case 4: set->sig[3] =3D op(set->sig[3]); \ - set->sig[2] =3D op(set->sig[2]); \ - fallthrough; \ - case 2: set->sig[1] =3D op(set->sig[1]); \ - fallthrough; \ - case 1: set->sig[0] =3D op(set->sig[0]); \ - break; \ default: \ for (i =3D 0; i < _NSIG_WORDS; i++) \ set->sig[i] =3D op(set->sig[i]); \ break; \ + case 4: \ + set->sig[3] =3D op(set->sig[3]); \ + fallthrough; \ + case 3: \ + set->sig[2] =3D op(set->sig[2]); \ + fallthrough; \ + case 2: \ + set->sig[1] =3D op(set->sig[1]); \ + fallthrough; \ + case 1: \ + set->sig[0] =3D op(set->sig[0]); \ + break; \ } \ } =20 @@ -268,9 +274,17 @@ static inline void sigemptyset(sigset_t *set) default: memset(set, 0, sizeof(sigset_t)); break; - case 2: set->sig[1] =3D 0; + case 4: + set->sig[3] =3D 0; + fallthrough; + case 3: + set->sig[2] =3D 0; fallthrough; - case 1: set->sig[0] =3D 0; + case 2: + set->sig[1] =3D 0; + fallthrough; + case 1: + set->sig[0] =3D 0; break; } } @@ -281,9 +295,17 @@ static inline void sigfillset(sigset_t *set) default: memset(set, -1, sizeof(sigset_t)); break; - case 2: set->sig[1] =3D -1; + case 4: + set->sig[3] =3D -1; fallthrough; - case 1: set->sig[0] =3D -1; + case 3: + set->sig[2] =3D -1; + fallthrough; + case 2: + set->sig[1] =3D -1; + fallthrough; + case 1: + set->sig[0] =3D -1; break; } } diff --git a/kernel/signal.c b/kernel/signal.c index 9421f1112b20..9c846a017201 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -143,6 +143,11 @@ static inline bool has_pending_signals(sigset_t *signa= l, sigset_t *blocked) ready |=3D signal->sig[0] &~ blocked->sig[0]; break; =20 + case 3: ready =3D signal->sig[2] &~ blocked->sig[2]; + ready |=3D signal->sig[1] &~ blocked->sig[1]; + ready |=3D signal->sig[0] &~ blocked->sig[0]; + break; + case 2: ready =3D signal->sig[1] &~ blocked->sig[1]; ready |=3D signal->sig[0] &~ blocked->sig[0]; break; --=20 2.30.2 From nobody Wed Jul 1 03:09:27 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DFD08C433EF for ; Mon, 3 Jan 2022 18:35:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235807AbiACSf3 (ORCPT ); Mon, 3 Jan 2022 13:35:29 -0500 Received: from drummond.us ([74.95.14.229]:40377 "EHLO talisker.home.drummond.us" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235702AbiACSfX (ORCPT ); Mon, 3 Jan 2022 13:35:23 -0500 X-Greylist: delayed 875 seconds by postgrey-1.27 at vger.kernel.org; Mon, 03 Jan 2022 13:35:12 EST Received: from talisker.home.drummond.us (localhost [127.0.0.1]) by talisker.home.drummond.us (8.15.2/8.15.2/Debian-20) with ESMTP id 203IKbNL983563; Mon, 3 Jan 2022 10:20:37 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=home.drummond.us; s=default; t=1641234037; bh=bSwluo0Aob4WYADzp3kAIHznX9//zY4MWY4AMAFc9h0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=y1Rc4BiSyaGNvVy4ergvgD57C2KAPogSVraoGKWZQbOP66D7gqBoxQfslTqrLVDnp 9Ykl0wJxzhE0WNWRSJNTZ8LmK+oEqdBCPvUHI+QSfHP9/FA32f+EAtOWAaq+RY0hwt 8zBC1v1Uu/UlgBDWLHSpoecuXcAdrpPqrZz9QM+a8VPSEAt3zKIG6ZTXmnUMiH/jtL qf6iH2z/UwVXvBUKsxOeQstmhsILFQyiHWmn28c9QERlt9cKJGiqrJVczxpxeFA/TY 1j6e77pATVRdiT1+CLO9C5qncNsFmudTkvxCaEbaZ9ZqEO06sVw4tUZPSGBUf9Dsft OY+j5YuRKkeAg== Received: (from walt@localhost) by talisker.home.drummond.us (8.15.2/8.15.2/Submit) id 203IKaLT983562; Mon, 3 Jan 2022 10:20:36 -0800 From: Walt Drummond To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Arnd Bergmann Cc: linux-kernel@vger.kernel.org, Walt Drummond , linux-arch@vger.kernel.org Subject: [RFC PATCH 6/8] signals: Round up _NSIG_WORDS Date: Mon, 3 Jan 2022 10:19:54 -0800 Message-Id: <20220103181956.983342-7-walt@drummond.us> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220103181956.983342-1-walt@drummond.us> References: <20220103181956.983342-1-walt@drummond.us> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" When needed, round _NSIG_WORDS up for generic and x86 architectures. Signed-off-by: Walt Drummond --- arch/x86/include/asm/signal.h | 2 +- include/uapi/asm-generic/signal.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h index 9bac7c6e524c..d8e2efe6cd46 100644 --- a/arch/x86/include/asm/signal.h +++ b/arch/x86/include/asm/signal.h @@ -16,7 +16,7 @@ # define _NSIG_BPW 64 #endif =20 -#define _NSIG_WORDS (_NSIG / _NSIG_BPW) +#define _NSIG_WORDS ((_NSIG + _NSIG_BPW - 1) / _NSIG_BPW) =20 typedef unsigned long old_sigset_t; /* at least 32 bits */ =20 diff --git a/include/uapi/asm-generic/signal.h b/include/uapi/asm-generic/s= ignal.h index f634822906e4..3c4cc9b8378e 100644 --- a/include/uapi/asm-generic/signal.h +++ b/include/uapi/asm-generic/signal.h @@ -6,7 +6,7 @@ =20 #define _NSIG 64 #define _NSIG_BPW __BITS_PER_LONG -#define _NSIG_WORDS (_NSIG / _NSIG_BPW) +#define _NSIG_WORDS ((_NSIG + _NSIG_BPW - 1) / _NSIG_BPW) =20 #define SIGHUP 1 #define SIGINT 2 --=20 2.30.2 From nobody Wed Jul 1 03:09:27 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4A533C433EF for ; Mon, 3 Jan 2022 18:34:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235687AbiACSez (ORCPT ); Mon, 3 Jan 2022 13:34:55 -0500 Received: from drummond.us ([74.95.14.229]:40377 "EHLO talisker.home.drummond.us" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235635AbiACSex (ORCPT ); Mon, 3 Jan 2022 13:34:53 -0500 X-Greylist: delayed 855 seconds by postgrey-1.27 at vger.kernel.org; Mon, 03 Jan 2022 13:34:52 EST Received: from talisker.home.drummond.us (localhost [127.0.0.1]) by talisker.home.drummond.us (8.15.2/8.15.2/Debian-20) with ESMTP id 203IKbFZ983578; Mon, 3 Jan 2022 10:20:37 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=home.drummond.us; s=default; t=1641234037; bh=wbAvlr10Npnd0/4eUIwpiZyKKD90fyNSB8BKvn+8AtE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cuzyqFBlViVazO6XJ+mK55v8TYoU8CSWPvRdS0zLHd2j/JRmo8KF8XPHNiDn7zK8f cKmWoGdlOtL+cYCiWXn0kFaBJFoDXFzVx/CwJtpUjqtzdDklwJeZsaKPnrhHMIUe/E X+0MBryfanY7Jvp2IFvl2tvrE2gZ/a0jv74eOnqpgaERy8SG0v03EsHZfuvinBjStp nAMPbwEXl0VbhyiPYC/MVtu+2OjqrYhLl4CJecOyf+fNVB3wrHaIwZLrl2zIht/lId IrdMi9fgeaOXX4b2ECra1EdLY0a0bdPgZHy1KGMB3KvjcdrqZ4r0gfPQXxoFaraRQ3 rPmms9nrwMkTg== Received: (from walt@localhost) by talisker.home.drummond.us (8.15.2/8.15.2/Submit) id 203IKb1X983577; Mon, 3 Jan 2022 10:20:37 -0800 From: Walt Drummond To: Luis Chamberlain , Kees Cook , Iurii Zaikin Cc: linux-kernel@vger.kernel.org, Walt Drummond , linux-fsdevel@vger.kernel.org Subject: [RFC PATCH 7/8] signals: Add signal debugging Date: Mon, 3 Jan 2022 10:19:55 -0800 Message-Id: <20220103181956.983342-8-walt@drummond.us> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220103181956.983342-1-walt@drummond.us> References: <20220103181956.983342-1-walt@drummond.us> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add CONFIG_SIGNALS_DEBUG, which provides /proc/sys/kern/sigset_size, /proc/sys/kern/compat_sigset_size (if CONFIG_COMPAT is enabled), /proc/sys/kern/max_sig and /proc/sys/kern/sigrtmax to indicate sigset sizes, max signal number (_NSIG) and value of SIGRTMAX respectively. This also adds /proc//signal, which sends a signal number to without going through libc. Signed-off-by: Walt Drummond --- fs/proc/base.c | 48 ++++++++++++++++++++++++++++++++++++++++++ include/linux/signal.h | 1 + kernel/signal.c | 15 ++++++++----- kernel/sysctl.c | 41 ++++++++++++++++++++++++++++++++++++ lib/Kconfig.debug | 10 +++++++++ 5 files changed, 110 insertions(+), 5 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 533d5836eb9a..75184abf9af1 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3165,6 +3165,51 @@ static int proc_stack_depth(struct seq_file *m, stru= ct pid_namespace *ns, } #endif /* CONFIG_STACKLEAK_METRICS */ =20 +#ifdef CONFIG_SIGNALS_DEBUG +static ssize_t proc_signal_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode =3D file_inode(file); + struct task_struct *task =3D get_proc_task(inode); + int ret; + pid_t pid; + unsigned long sig =3D (unsigned long) -1; + + if (!task) + return -ESRCH; + if (*ppos !=3D 0) + /* No partial writes. */ + return -EINVAL; + + if (count > 4 || count <=3D 1) + return -EINVAL; + + ret =3D kstrtoul_from_user(buf, count, 10, &sig); + if (ret !=3D 0) + return -EINVAL; + + if (!valid_signal(sig)) + return -EINVAL; + if (sig =3D=3D 0) + return count; + + pid =3D pid_vnr(get_task_pid(task, PIDTYPE_PID)); + if (pid =3D=3D 0) + return -EINVAL; + + ret =3D do_sys_kill(pid, sig); + if (ret) + return ret; + + return count; +} + +static const struct file_operations proc_signal_operations =3D { + .write =3D proc_signal_write, + .llseek =3D noop_llseek, +}; +#endif /* CONFIG_SIGNALS_DEBUG */ + /* * Thread groups */ @@ -3281,6 +3326,9 @@ static const struct pid_entry tgid_base_stuff[] =3D { #ifdef CONFIG_SECCOMP_CACHE_DEBUG ONE("seccomp_cache", S_IRUSR, proc_pid_seccomp_cache), #endif +#ifdef CONFIG_SIGNALS_DEBUG + REG("signal", S_IWUSR, proc_signal_operations), +#endif }; =20 static int proc_tgid_base_readdir(struct file *file, struct dir_context *c= tx) diff --git a/include/linux/signal.h b/include/linux/signal.h index 4084b765a6cc..b77f9472a37c 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -446,6 +446,7 @@ extern bool get_signal(struct ksignal *ksig); extern void signal_setup_done(int failed, struct ksignal *ksig, int steppi= ng); extern void exit_signals(struct task_struct *tsk); extern void kernel_sigaction(int, __sighandler_t); +extern int do_sys_kill(pid_t pid, int sig); =20 #define SIG_KTHREAD ((__force __sighandler_t)2) #define SIG_KTHREAD_KERNEL ((__force __sighandler_t)3) diff --git a/kernel/signal.c b/kernel/signal.c index 9c846a017201..1ed392df55fb 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -3755,6 +3755,15 @@ static inline void prepare_kill_siginfo(int sig, str= uct kernel_siginfo *info) info->si_uid =3D from_kuid_munged(current_user_ns(), current_uid()); } =20 +int do_sys_kill(pid_t pid, int sig) +{ + struct kernel_siginfo info; + + prepare_kill_siginfo(sig, &info); + + return kill_something_info(sig, &info, pid); +} + /** * sys_kill - send a signal to a process * @pid: the PID of the process @@ -3762,11 +3771,7 @@ static inline void prepare_kill_siginfo(int sig, str= uct kernel_siginfo *info) */ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig) { - struct kernel_siginfo info; - - prepare_kill_siginfo(sig, &info); - - return kill_something_info(sig, &info, pid); + return do_sys_kill(pid, sig); } =20 /* diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 083be6af29d7..0d7e1d16b75b 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -139,6 +139,15 @@ static int minolduid; static int ngroups_max =3D NGROUPS_MAX; static const int cap_last_cap =3D CAP_LAST_CAP; =20 +#ifdef CONFIG_SIGNALS_DEBUG +static int max_signal =3D _NSIG; +static int sigrtmax =3D SIGRTMAX; +static int sigset_size =3D sizeof(sigset_t); +# ifdef CONFIG_COMPAT +static int compat_sigset_size =3D sizeof(compat_sigset_t); +# endif +#endif + /* * This is needed for proc_doulongvec_minmax of sysctl_hung_task_timeout_s= ecs * and hung_task_check_interval_secs @@ -2717,6 +2726,38 @@ static struct ctl_table kern_table[] =3D { .extra1 =3D SYSCTL_ZERO, .extra2 =3D SYSCTL_ONE, }, +#endif +#ifdef CONFIG_SIGNALS_DEBUG + { + .procname =3D "max_signal", + .data =3D &max_signal, + .maxlen =3D sizeof(int), + .mode =3D 0444, + .proc_handler =3D proc_dointvec, + }, + { + .procname =3D "sigrtmax", + .data =3D &sigrtmax, + .maxlen =3D sizeof(int), + .mode =3D 0444, + .proc_handler =3D proc_dointvec, + }, + { + .procname =3D "sigset_size", + .data =3D &sigset_size, + .maxlen =3D sizeof(int), + .mode =3D 0444, + .proc_handler =3D proc_dointvec, + }, +# ifdef CONFIG_COMPAT + { + .procname =3D "compat_sigset_size", + .data =3D &compat_sigset_size, + .maxlen =3D sizeof(int), + .mode =3D 0444, + .proc_handler =3D proc_dointvec, + }, +# endif #endif { } }; diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 2a9b6dcdac4f..c433356c1070 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2639,4 +2639,14 @@ endmenu # "Kernel Testing and Coverage" =20 source "Documentation/Kconfig" =20 +config SIGNALS_DEBUG + bool "Enable basic signals debugging" + default n + help + Provides several files in /proc to aid in debugging changes to + the signals code: /proc/sys/kernel/max_signal, + /proc/sys/kernel/sigrtmax and /proc/sys/kernel/sigset_size. + Also adds /proc//signal to allow sending a signal number + to without going through libc. + endmenu # Kernel hacking --=20 2.30.2 From nobody Wed Jul 1 03:09:27 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 998C4C433F5 for ; Mon, 3 Jan 2022 18:35:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235792AbiACSfc (ORCPT ); Mon, 3 Jan 2022 13:35:32 -0500 Received: from drummond.us ([74.95.14.229]:40377 "EHLO talisker.home.drummond.us" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S235794AbiACSf3 (ORCPT ); Mon, 3 Jan 2022 13:35:29 -0500 X-Greylist: delayed 863 seconds by postgrey-1.27 at vger.kernel.org; Mon, 03 Jan 2022 13:35:25 EST Received: from talisker.home.drummond.us (localhost [127.0.0.1]) by talisker.home.drummond.us (8.15.2/8.15.2/Debian-20) with ESMTP id 203IKdbf983592; Mon, 3 Jan 2022 10:20:39 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=home.drummond.us; s=default; t=1641234039; bh=Fbu0kfS/jXmJhQym0vqqes0s23iVHLmqEEMrCQGAdEw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=puCaRPCWLX1nSm5lhC55HwmV/7Txs+TjPpmwcG9+EkWSeTh08EPxjCIxzdw+lTkK7 tqFaIbsJ22BjxHNdfSfq6/cXJ10TpS7Tgg0eVX8HpglFHgmIvJvkNPeqOuAIfhLHhb 4PosMYz7PReoVNVpG90iQBUZR9xsGyTbYaq12XsFoFJIf8djjknVVHj1JWKWrARAp5 Fbje2RvzG7z3cI7DnLgyw40pEMlEv3KLyc6Jbc3dp+3zDnQAw1KI38GqPtPKKCgm5K lwWQyIlguZS1wIBYlQb4JVJP0Go+aCLK2u6bGMuR0jTJfySuX5OvkqOU5dQgyQcRKk 3C1iw0sur9T6g== Received: (from walt@localhost) by talisker.home.drummond.us (8.15.2/8.15.2/Submit) id 203IKduX983591; Mon, 3 Jan 2022 10:20:39 -0800 From: Walt Drummond To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Greg Kroah-Hartman , Jiri Slaby , Arnd Bergmann , Peter Zijlstra , Juri Lelli , Vincent Guittot , Dietmar Eggemann , Steven Rostedt , Ben Segall , Mel Gorman , Daniel Bristot de Oliveira Cc: linux-kernel@vger.kernel.org, Walt Drummond , linux-fsdevel@vger.kernel.org, linux-arch@vger.kernel.org Subject: [RFC PATCH 8/8] signals: Support BSD VSTATUS, KERNINFO and SIGINFO Date: Mon, 3 Jan 2022 10:19:56 -0800 Message-Id: <20220103181956.983342-9-walt@drummond.us> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220103181956.983342-1-walt@drummond.us> References: <20220103181956.983342-1-walt@drummond.us> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Support TTY VSTATUS character, NOKERNINFO local control bit and the signal SIGINFO, all as in 4.3BSD. Signed-off-by: Walt Drummond --- arch/x86/include/asm/signal.h | 2 +- arch/x86/include/uapi/asm/signal.h | 4 +- drivers/tty/Makefile | 2 +- drivers/tty/n_tty.c | 21 +++++ drivers/tty/tty_io.c | 10 ++- drivers/tty/tty_ioctl.c | 4 + drivers/tty/tty_status.c | 135 ++++++++++++++++++++++++++++ fs/proc/array.c | 29 +----- include/asm-generic/termios.h | 4 +- include/linux/sched.h | 52 ++++++++++- include/linux/signal.h | 4 + include/linux/tty.h | 8 ++ include/uapi/asm-generic/ioctls.h | 2 + include/uapi/asm-generic/signal.h | 6 +- include/uapi/asm-generic/termbits.h | 34 +++---- 15 files changed, 264 insertions(+), 53 deletions(-) create mode 100644 drivers/tty/tty_status.c diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h index d8e2efe6cd46..0a01877c11ab 100644 --- a/arch/x86/include/asm/signal.h +++ b/arch/x86/include/asm/signal.h @@ -8,7 +8,7 @@ /* Most things should be clean enough to redefine this at will, if care is taken to make libc match. */ =20 -#define _NSIG 64 +#define _NSIG 65 =20 #ifdef __i386__ # define _NSIG_BPW 32 diff --git a/arch/x86/include/uapi/asm/signal.h b/arch/x86/include/uapi/asm= /signal.h index 164a22a72984..60dca62d3dcf 100644 --- a/arch/x86/include/uapi/asm/signal.h +++ b/arch/x86/include/uapi/asm/signal.h @@ -60,7 +60,9 @@ typedef unsigned long sigset_t; =20 /* These should not be considered constants from userland. */ #define SIGRTMIN 32 -#define SIGRTMAX _NSIG +#define SIGRTMAX 64 + +#define SIGINFO 65 =20 #define SA_RESTORER 0x04000000 =20 diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index a2bd75fbaaa4..d50ba690bb87 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_TTY) +=3D tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \ tty_buffer.o tty_port.o tty_mutex.o \ tty_ldsem.o tty_baudrate.o tty_jobctrl.o \ - n_null.o + n_null.o tty_status.o obj-$(CONFIG_LEGACY_PTYS) +=3D pty.o obj-$(CONFIG_UNIX98_PTYS) +=3D pty.o obj-$(CONFIG_AUDIT) +=3D tty_audit.o diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 0ec93f1a61f5..b510e01289fd 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1334,6 +1334,24 @@ static void n_tty_receive_char_special(struct tty_st= ruct *tty, unsigned char c) commit_echoes(tty); return; } +#ifdef VSTATUS + if (c =3D=3D STATUS_CHAR(tty)) { + /* Do the status message first and then send + * the signal, otherwise signal delivery can + * change the process state making the status + * message misleading. Also, use __isig() and + * not sig(), as if we flush the tty we can + * lose parts of the message. + */ + + if (!L_NOKERNINFO(tty)) + tty_status(tty); +# if defined(SIGINFO) && SIGINFO !=3D SIGPWR + __isig(SIGINFO, tty); +# endif + return; + } +#endif /* VSTATUS */ if (c =3D=3D '\n') { if (L_ECHO(tty) || L_ECHONL(tty)) { echo_char_raw('\n', ldata); @@ -1763,6 +1781,9 @@ static void n_tty_set_termios(struct tty_struct *tty,= struct ktermios *old) set_bit(EOF_CHAR(tty), ldata->char_map); set_bit('\n', ldata->char_map); set_bit(EOL_CHAR(tty), ldata->char_map); +#ifdef VSTATUS + set_bit(STATUS_CHAR(tty), ldata->char_map); +#endif if (L_IEXTEN(tty)) { set_bit(WERASE_CHAR(tty), ldata->char_map); set_bit(LNEXT_CHAR(tty), ldata->char_map); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 6616d4a0d41d..8e488ecba330 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -120,18 +120,26 @@ #define TTY_PARANOIA_CHECK 1 #define CHECK_TTY_COUNT 1 =20 +/* Less ugly than an ifdef in the middle of the initalizer below, maybe? */ +#ifdef NOKERNINFO +# define __NOKERNINFO NOKERNINFO +#else +# define __NOKERNINFO 0 +#endif + struct ktermios tty_std_termios =3D { /* for the benefit of tty drivers */ .c_iflag =3D ICRNL | IXON, .c_oflag =3D OPOST | ONLCR, .c_cflag =3D B38400 | CS8 | CREAD | HUPCL, .c_lflag =3D ISIG | ICANON | ECHO | ECHOE | ECHOK | - ECHOCTL | ECHOKE | IEXTEN, + ECHOCTL | ECHOKE | IEXTEN | __NOKERNINFO, .c_cc =3D INIT_C_CC, .c_ispeed =3D 38400, .c_ospeed =3D 38400, /* .c_line =3D N_TTY, */ }; EXPORT_SYMBOL(tty_std_termios); +#undef __NOKERNINFO =20 /* This list gets poked at by procfs and various bits of boot up code. This * could do with some rationalisation such as pulling the tty proc function diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 507a25d692bb..b250eabca1ba 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -809,6 +809,10 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file= *file, if (get_user(arg, (unsigned int __user *) arg)) return -EFAULT; return tty_change_softcar(real_tty, arg); +#ifdef TIOCSTAT + case TIOCSTAT: + return tty_status(real_tty); +#endif default: return -ENOIOCTLCMD; } diff --git a/drivers/tty/tty_status.c b/drivers/tty/tty_status.c new file mode 100644 index 000000000000..a9600f5bd48c --- /dev/null +++ b/drivers/tty/tty_status.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-1.0+ +/* + * tty_status.c --- implements VSTATUS and TIOCSTAT from BSD4.3/4.4 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MSGLEN (160 + TASK_COMM_LEN) + +inline unsigned long getRSSk(struct mm_struct *mm) +{ + if (mm =3D=3D NULL) + return 0; + return get_mm_rss(mm) * PAGE_SIZE / 1024; +} + +inline long nstoms(long l) +{ + l /=3D NSEC_PER_MSEC * 10; + if (l < 10) + l *=3D 10; + return l; +} + +inline struct task_struct *compare(struct task_struct *new, + struct task_struct *old) +{ + unsigned int ostate, nstate; + + if (old =3D=3D NULL) + return new; + + ostate =3D task_state_index(old); + nstate =3D task_state_index(new); + + if (ostate =3D=3D nstate) { + if (old->start_time > new->start_time) + return old; + return new; + } + + if (ostate < nstate) + return old; + + return new; +} + +struct task_struct *pick_process(struct pid *pgrp) +{ + struct task_struct *p, *winner =3D NULL; + + read_lock(&tasklist_lock); + do_each_pid_task(pgrp, PIDTYPE_PGID, p) { + winner =3D compare(p, winner); + } while_each_pid_task(pgrp, PIDTYPE_PGID, p); + read_unlock(&tasklist_lock); + + return winner; +} + +int tty_status(struct tty_struct *tty) +{ + char tname[TASK_COMM_LEN]; + unsigned long loadavg[3]; + uint64_t pcpu, cputime, wallclock; + struct task_struct *p; + struct rusage rusage; + struct timespec64 utime, stime, rtime; + char msg[MSGLEN] =3D {0}; + int len =3D 0; + + if (tty =3D=3D NULL) + return -ENOTTY; + + get_avenrun(loadavg, FIXED_1/200, 0); + len +=3D scnprintf((char *)&msg[len], MSGLEN - len, "load: %lu.%02lu ", + LOAD_INT(loadavg[0]), LOAD_FRAC(loadavg[0])); + + if (tty->ctrl.session =3D=3D NULL) { + len +=3D scnprintf((char *)&msg[len], MSGLEN - len, + "not a controlling terminal"); + goto print; + } + + if (tty->ctrl.pgrp =3D=3D NULL) { + len +=3D scnprintf((char *)&msg[len], MSGLEN - len, + "no foreground process group"); + goto print; + } + + p =3D pick_process(tty->ctrl.pgrp); + if (p =3D=3D NULL) { + len +=3D scnprintf((char *)&msg[len], MSGLEN - len, + "empty foreground process group"); + goto print; + } + + get_task_comm(tname, p); + getrusage(p, RUSAGE_BOTH, &rusage); + wallclock =3D ktime_get_ns() - p->start_time; + + utime.tv_sec =3D rusage.ru_utime.tv_sec; + utime.tv_nsec =3D rusage.ru_utime.tv_usec * NSEC_PER_USEC; + stime.tv_sec =3D rusage.ru_stime.tv_sec; + stime.tv_nsec =3D rusage.ru_stime.tv_usec * NSEC_PER_USEC; + rtime =3D ns_to_timespec64(wallclock); + + cputime =3D timespec64_to_ns(&utime) + timespec64_to_ns(&stime); + pcpu =3D div64_u64(cputime * 100, wallclock); + + len +=3D scnprintf((char *)&msg[len], MSGLEN - len, + /* task, PID, task state */ + "cmd: %s %d [%s] " + /* rtime, utime, stime, %cpu, rss */ + "%llu.%02lur %llu.%02luu %llu.%02lus %llu%% %luk", + tname, task_pid_vnr(p), (char *)get_task_state_name(p), + rtime.tv_sec, nstoms(rtime.tv_nsec), + utime.tv_sec, nstoms(utime.tv_nsec), + stime.tv_sec, nstoms(stime.tv_nsec), + pcpu, getRSSk(p->mm)); + +print: + len +=3D scnprintf((char *)&msg[len], MSGLEN - len, "\r\n"); + tty_write_message(tty, msg); + + return 0; +} diff --git a/fs/proc/array.c b/fs/proc/array.c index f37c03077b58..eb14306cdde2 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include @@ -111,34 +112,6 @@ void proc_task_name(struct seq_file *m, struct task_st= ruct *p, bool escape) seq_printf(m, "%.64s", tcomm); } =20 -/* - * The task state array is a strange "bitmap" of - * reasons to sleep. Thus "running" is zero, and - * you can test for combinations of others with - * simple bit tests. - */ -static const char * const task_state_array[] =3D { - - /* states in TASK_REPORT: */ - "R (running)", /* 0x00 */ - "S (sleeping)", /* 0x01 */ - "D (disk sleep)", /* 0x02 */ - "T (stopped)", /* 0x04 */ - "t (tracing stop)", /* 0x08 */ - "X (dead)", /* 0x10 */ - "Z (zombie)", /* 0x20 */ - "P (parked)", /* 0x40 */ - - /* states beyond TASK_REPORT: */ - "I (idle)", /* 0x80 */ -}; - -static inline const char *get_task_state(struct task_struct *tsk) -{ - BUILD_BUG_ON(1 + ilog2(TASK_REPORT_MAX) !=3D ARRAY_SIZE(task_state_array)= ); - return task_state_array[task_state_index(tsk)]; -} - static inline void task_state(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *p) { diff --git a/include/asm-generic/termios.h b/include/asm-generic/termios.h index b1398d0d4a1d..9b080e1a82d4 100644 --- a/include/asm-generic/termios.h +++ b/include/asm-generic/termios.h @@ -10,9 +10,9 @@ eof=3D^D vtime=3D\0 vmin=3D\1 sxtc=3D\0 start=3D^Q stop=3D^S susp=3D^Z eol=3D\0 reprint=3D^R discard=3D^U werase=3D^W lnext=3D^V - eol2=3D\0 + eol2=3D\0 status=3D^T */ -#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\02= 6\0" +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\02= 6\0\024" =20 /* * Translate a "termio" structure into a "termios". Ugh. diff --git a/include/linux/sched.h b/include/linux/sched.h index c1a927ddec64..2171074ec8f5 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -70,7 +70,7 @@ struct task_group; =20 /* * Task state bitmask. NOTE! These bits are also - * encoded in fs/proc/array.c: get_task_state(). + * encoded in get_task_state(). * * We have two separate sets of flags: task->state * is about runnability, while task->exit_state are @@ -1643,6 +1643,56 @@ static inline char task_state_to_char(struct task_st= ruct *tsk) return task_index_to_char(task_state_index(tsk)); } =20 +static inline const char *get_task_state_name(struct task_struct *tsk) +{ + static const char * const task_state_array[] =3D { + + /* states in TASK_REPORT: */ + "running", /* 0x00 */ + "sleeping", /* 0x01 */ + "disk sleep", /* 0x02 */ + "stopped", /* 0x04 */ + "tracing stop", /* 0x08 */ + "dead", /* 0x10 */ + "zombie", /* 0x20 */ + "parked", /* 0x40 */ + + /* states beyond TASK_REPORT: */ + "idle", /* 0x80 */ + }; + + BUILD_BUG_ON(1 + ilog2(TASK_REPORT_MAX) !=3D ARRAY_SIZE(task_state_array)= ); + return task_state_array[task_state_index(tsk)]; +} + +static inline const char *get_task_state(struct task_struct *tsk) +{ + /* + * The task state array is a strange "bitmap" of + * reasons to sleep. Thus "running" is zero, and + * you can test for combinations of others with + * simple bit tests. + */ + static const char * const task_state_array[] =3D { + + /* states in TASK_REPORT: */ + "R (running)", /* 0x00 */ + "S (sleeping)", /* 0x01 */ + "D (disk sleep)", /* 0x02 */ + "T (stopped)", /* 0x04 */ + "t (tracing stop)", /* 0x08 */ + "X (dead)", /* 0x10 */ + "Z (zombie)", /* 0x20 */ + "P (parked)", /* 0x40 */ + + /* states beyond TASK_REPORT: */ + "I (idle)", /* 0x80 */ + }; + + BUILD_BUG_ON(1 + ilog2(TASK_REPORT_MAX) !=3D ARRAY_SIZE(task_state_array)= ); + return task_state_array[task_state_index(tsk)]; +} + /** * is_global_init - check if a task structure is init. Since init * is free to have sub-threads we need to check tgid. diff --git a/include/linux/signal.h b/include/linux/signal.h index b77f9472a37c..76bda1a20578 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -541,6 +541,7 @@ extern bool unhandled_signal(struct task_struct *tsk, i= nt sig); * | non-POSIX signal | default action | * +--------------------+------------------+ * | SIGEMT | coredump | + * | SIGINFO | ignore | * +--------------------+------------------+ * * (+) For SIGKILL and SIGSTOP the action is "always", not just "default". @@ -567,6 +568,9 @@ static inline int sig_kernel_ignore(unsigned long sig) return sig =3D=3D SIGCONT || sig =3D=3D SIGCHLD || sig =3D=3D SIGWINCH || +#if defined(SIGINFO) && SIGINFO !=3D SIGPWR + sig =3D=3D SIGINFO || +#endif sig =3D=3D SIGURG; } =20 diff --git a/include/linux/tty.h b/include/linux/tty.h index 168e57e40bbb..943d85aa471c 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -49,6 +49,9 @@ #define WERASE_CHAR(tty) ((tty)->termios.c_cc[VWERASE]) #define LNEXT_CHAR(tty) ((tty)->termios.c_cc[VLNEXT]) #define EOL2_CHAR(tty) ((tty)->termios.c_cc[VEOL2]) +#ifdef VSTATUS +#define STATUS_CHAR(tty) ((tty)->termios.c_cc[VSTATUS]) +#endif =20 #define _I_FLAG(tty, f) ((tty)->termios.c_iflag & (f)) #define _O_FLAG(tty, f) ((tty)->termios.c_oflag & (f)) @@ -114,6 +117,9 @@ #define L_PENDIN(tty) _L_FLAG((tty), PENDIN) #define L_IEXTEN(tty) _L_FLAG((tty), IEXTEN) #define L_EXTPROC(tty) _L_FLAG((tty), EXTPROC) +#ifdef NOKERNINFO +#define L_NOKERNINFO(tty) _L_FLAG((tty), NOKERNINFO) +#endif =20 struct device; struct signal_struct; @@ -428,4 +434,6 @@ extern void tty_lock_slave(struct tty_struct *tty); extern void tty_unlock_slave(struct tty_struct *tty); extern void tty_set_lock_subclass(struct tty_struct *tty); =20 +extern int tty_status(struct tty_struct *tty); + #endif diff --git a/include/uapi/asm-generic/ioctls.h b/include/uapi/asm-generic/i= octls.h index cdc9f4ca8c27..baa2b8d42679 100644 --- a/include/uapi/asm-generic/ioctls.h +++ b/include/uapi/asm-generic/ioctls.h @@ -97,6 +97,8 @@ =20 #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +/* Some architectures use 0x545E for FIOQSIZE */ +#define TIOCSTAT 0x545F /* display process group stats on tty */ =20 /* * Some arches already define FIOQSIZE due to a historical diff --git a/include/uapi/asm-generic/signal.h b/include/uapi/asm-generic/s= ignal.h index 3c4cc9b8378e..0b771eb1db94 100644 --- a/include/uapi/asm-generic/signal.h +++ b/include/uapi/asm-generic/signal.h @@ -4,7 +4,7 @@ =20 #include =20 -#define _NSIG 64 +#define _NSIG 65 #define _NSIG_BPW __BITS_PER_LONG #define _NSIG_WORDS ((_NSIG + _NSIG_BPW - 1) / _NSIG_BPW) =20 @@ -49,9 +49,11 @@ /* These should not be considered constants from userland. */ #define SIGRTMIN 32 #ifndef SIGRTMAX -#define SIGRTMAX _NSIG +#define SIGRTMAX 64 #endif =20 +#define SIGINFO 65 + #if !defined MINSIGSTKSZ || !defined SIGSTKSZ #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 diff --git a/include/uapi/asm-generic/termbits.h b/include/uapi/asm-generic= /termbits.h index 2fbaf9ae89dd..cb4e9c6d629f 100644 --- a/include/uapi/asm-generic/termbits.h +++ b/include/uapi/asm-generic/termbits.h @@ -58,6 +58,7 @@ struct ktermios { #define VWERASE 14 #define VLNEXT 15 #define VEOL2 16 +#define VSTATUS 17 =20 /* c_iflag bits */ #define IGNBRK 0000001 @@ -164,22 +165,23 @@ struct ktermios { #define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ =20 /* c_lflag bits */ -#define ISIG 0000001 -#define ICANON 0000002 -#define XCASE 0000004 -#define ECHO 0000010 -#define ECHOE 0000020 -#define ECHOK 0000040 -#define ECHONL 0000100 -#define NOFLSH 0000200 -#define TOSTOP 0000400 -#define ECHOCTL 0001000 -#define ECHOPRT 0002000 -#define ECHOKE 0004000 -#define FLUSHO 0010000 -#define PENDIN 0040000 -#define IEXTEN 0100000 -#define EXTPROC 0200000 +#define ISIG 0000001 +#define ICANON 0000002 +#define XCASE 0000004 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define IEXTEN 0100000 +#define EXTPROC 0200000 +#define NOKERNINFO 0400000 =20 /* tcflow() and TCXONC use these */ #define TCOOFF 0 --=20 2.30.2