summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/ptrace.c49
1 files changed, 37 insertions, 12 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 84b1367935e4..a7786b34b485 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -880,6 +880,22 @@ static int ptrace_regset(struct task_struct *task, int req, unsigned int type,
EXPORT_SYMBOL_GPL(task_user_regset_view);
#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,
unsigned long addr, unsigned long data)
{
@@ -951,18 +967,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);
-
- ret = 0;
+ ret = ptrace_setsigmask(child, &new_set);
break;
}
@@ -1191,7 +1196,9 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
compat_ulong_t addr, compat_ulong_t data)
{
compat_ulong_t __user *datap = compat_ptr(data);
+ compat_sigset_t set32;
compat_ulong_t word;
+ sigset_t new_set;
siginfo_t siginfo;
int ret;
@@ -1233,6 +1240,24 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
else
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: