Commit 810edb50 authored by James Morse's avatar James Morse Committed by Jinjie Ruan
Browse files

ptrace: Add compat PTRACE_{G,S}ETSIGMASK handlers

maillist inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8JVJ3
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: 29000cae ("ptrace: add ability to get/set signal-blocked mask")
CC: Andrey Vagin <avagin@openvz.org>
Signed-off-by: default avatarJames Morse <james.morse@arm.com>

Yury:
Replace sigset_{to,from}_compat() with new {get,put}_compat_sigset()
Signed-off-by: default avatarYury Norov <ynorov@caviumnetworks.com>
Signed-off-by: default avatarYury Norov <ynorov@marvell.com>
Signed-off-by: default avatarXiongfeng Wang <wangxiongfeng2@huawei.com>
Acked-by: default avatarXie XiuQi <xiexiuqi@huawei.com>
Signed-off-by: default avatarChen Jun <chenjun102@huawei.com>
Patchwork Links: http://patchwork.huawei.com/project/hulk5.10/list/?series=12937


Signed-off-by: default avatarChen Jiahao <chenjiahao16@huawei.com>
Signed-off-by: default avatarJinjie Ruan <ruanjinjie@huawei.com>
parent fb3d7778
Loading
Loading
Loading
Loading
+38 −14
Original line number Diff line number Diff line
@@ -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: