提交 9bcdb3c0 编写于 作者: J James Morse 提交者: Yang Yingliang

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

hulk inclusion
category: feature
bugzilla: NA
CVE: NA
---------------------------

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: NJames Morse <james.morse@arm.com>

Yury:
Replace sigset_{to,from}_compat() with new {get,put}_compat_sigset()
Signed-off-by: NYury Norov <ynorov@caviumnetworks.com>

 Conflicts:
	kernel/ptrace.c
[wangxiongfeng: conflicts because of the following patch
commit 4afa2bd35  ptrace: take into account saved_sigmask in PTRACE{GET,
SET}SIGMASK
Fix it by calling 'clear_tsk_restore_sigmask()' after
'ptrace_setsigmask()']
Signed-off-by: NXiongfeng Wang <wangxiongfeng2@huawei.com>
Reviewed-by: NHanjun Guo &lt;guohanjun@huawei.com <mailto:guohanjun@huawei.com&gt;>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 a6e4e630
...@@ -900,6 +900,22 @@ static int ptrace_regset(struct task_struct *task, int req, unsigned int type, ...@@ -900,6 +900,22 @@ static int ptrace_regset(struct task_struct *task, int req, unsigned int type,
EXPORT_SYMBOL_GPL(task_user_regset_view); EXPORT_SYMBOL_GPL(task_user_regset_view);
#endif #endif
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);
return 0;
}
int ptrace_request(struct task_struct *child, long request, int ptrace_request(struct task_struct *child, long request,
unsigned long addr, unsigned long data) unsigned long addr, unsigned long data)
{ {
...@@ -979,20 +995,10 @@ int ptrace_request(struct task_struct *child, long request, ...@@ -979,20 +995,10 @@ int ptrace_request(struct task_struct *child, long request,
break; break;
} }
sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); ret = ptrace_setsigmask(child, &new_set);
/*
* 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); clear_tsk_restore_sigmask(child);
ret = 0;
break; break;
} }
...@@ -1211,6 +1217,7 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, ...@@ -1211,6 +1217,7 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
{ {
compat_ulong_t __user *datap = compat_ptr(data); compat_ulong_t __user *datap = compat_ptr(data);
compat_ulong_t word; compat_ulong_t word;
sigset_t new_set;
siginfo_t siginfo; siginfo_t siginfo;
int ret; int ret;
...@@ -1251,6 +1258,24 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request, ...@@ -1251,6 +1258,24 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
else else
ret = ptrace_setsiginfo(child, &siginfo); ret = ptrace_setsiginfo(child, &siginfo);
break; 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 #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
case PTRACE_GETREGSET: case PTRACE_GETREGSET:
case PTRACE_SETREGSET: case PTRACE_SETREGSET:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册