
From: James Morse <james.morse@arm.com> maillist inclusion category: feature bugzilla: 46790 CVE: NA Reference: https://github.com/norov/linux/commits/ilp32-5.2 -------------------------------- compat_ptrace_request() lacks handlers for PTRACE_{G,S}ETSIGMASK, instead using those in ptrace_request(). The compat variant should read a compat_sigset_t from userspace instead of ptrace_request()s sigset_t. While compat_sigset_t is the same size as sigset_t, it is defined as 2xu32, instead of a single u64. On a big-endian CPU this means that compat_sigset_t is passed to user-space using middle-endianness, where the least-significant u32 is written most significant byte first. If ptrace_request()s code is used userspace will read the most significant u32 where it expected the least significant. Instead of duplicating ptrace_request()s code as a special case in the arch code, handle it here. Fixes: 29000caecbe87 ("ptrace: add ability to get/set signal-blocked mask") CC: Andrey Vagin <avagin@openvz.org> Signed-off-by: James Morse <james.morse@arm.com> Yury: Replace sigset_{to,from}_compat() with new {get,put}_compat_sigset() Signed-off-by: Yury Norov <ynorov@caviumnetworks.com> Signed-off-by: Yury Norov <ynorov@marvell.com> Signed-off-by: Xiongfeng Wang <wangxiongfeng2@huawei.com> Acked-by: Xie XiuQi <xiexiuqi@huawei.com> Signed-off-by: Chen Jun <chenjun102@huawei.com> Patchwork Links: http://patchwork.huawei.com/project/hulk5.10/list/?series=12937 Signed-off-by: Chen Jiahao <chenjiahao16@huawei.com> --- kernel/ptrace.c | 52 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 443057bee87c..a8682842c840 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -1028,6 +1028,24 @@ ptrace_get_syscall_info(struct task_struct *child, unsigned long user_size, } #endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ +static int ptrace_setsigmask(struct task_struct *child, sigset_t *new_set) +{ + sigdelsetmask(new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); + + /* + * Every thread does recalc_sigpending() after resume, so + * retarget_shared_pending() and recalc_sigpending() are not + * called here. + */ + spin_lock_irq(&child->sighand->siglock); + child->blocked = *new_set; + spin_unlock_irq(&child->sighand->siglock); + + clear_tsk_restore_sigmask(child); + + return 0; +} + int ptrace_request(struct task_struct *child, long request, unsigned long addr, unsigned long data) { @@ -1106,20 +1124,7 @@ int ptrace_request(struct task_struct *child, long request, break; } - sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); - - /* - * Every thread does recalc_sigpending() after resume, so - * retarget_shared_pending() and recalc_sigpending() are not - * called here. - */ - spin_lock_irq(&child->sighand->siglock); - child->blocked = new_set; - spin_unlock_irq(&child->sighand->siglock); - - clear_tsk_restore_sigmask(child); - - ret = 0; + ret = ptrace_setsigmask(child, &new_set); break; } @@ -1341,6 +1346,7 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, { compat_ulong_t __user *datap = compat_ptr(data); compat_ulong_t word; + sigset_t new_set; kernel_siginfo_t siginfo; int ret; @@ -1380,6 +1386,24 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, if (!ret) ret = ptrace_setsiginfo(child, &siginfo); break; + case PTRACE_GETSIGMASK: + if (addr != sizeof(compat_sigset_t)) + return -EINVAL; + + ret = put_compat_sigset((compat_sigset_t __user *) datap, + &child->blocked, sizeof(compat_sigset_t)); + break; + case PTRACE_SETSIGMASK: + if (addr != sizeof(compat_sigset_t)) + return -EINVAL; + + ret = get_compat_sigset(&new_set, + (compat_sigset_t __user *) datap); + if (ret) + break; + + ret = ptrace_setsigmask(child, &new_set); + break; #ifdef CONFIG_HAVE_ARCH_TRACEHOOK case PTRACE_GETREGSET: case PTRACE_SETREGSET: -- 2.34.1