Add the new helper, ptrace_signal_wake_up(), change ptrace.c/signal.c
to use it instead of signal_wake_up() to wake up a STOPPED/TRACED task.

The new helper does almost the same, except:

        - it doesn't use the TASK_WAKEKILL bit to wake up the TRACED
          or STOPPED task, it uses __TASK_STOPPED | __TASK_TRACED
          explicitly. This is what ptrace actually wants, it should
          never wake up a TASK_KILLABLE task.

          This should be cleanuped upatream, signal_wake_up() should
          take the state as an argument, not a boolean. Until then
          we add a new static helper.

        - it uses wake_up_quiescent() instead of wake_up_state().

Thereafter every change from STOPPED/TRACED to RUNNING is done via
wake_up_quiescent().

Signed-off-by: Oleg Nesterov <o...@redhat.com>
---
 include/linux/ptrace.h |    1 +
 kernel/ptrace.c        |   20 ++++++++++++++++----
 kernel/signal.c        |    2 +-
 3 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 800f113..6d9282a 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -113,6 +113,7 @@
 #include <linux/compiler.h>            /* For unlikely.  */
 #include <linux/sched.h>               /* For struct task_struct.  */
 
+extern void ptrace_signal_wake_up(struct task_struct *p, int quiescent);
 
 extern long arch_ptrace(struct task_struct *child, long request,
                        unsigned long addr, unsigned long data);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 4194664..1a50090 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -25,6 +25,18 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/cn_proc.h>
 
+void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
+{
+       unsigned int state;
+
+       set_tsk_thread_flag(p, TIF_SIGPENDING);
+
+       state = TASK_INTERRUPTIBLE;
+       if (quiescent)
+               state |= (__TASK_STOPPED | __TASK_TRACED);
+       if (!wake_up_quiescent(p, state))
+               kick_process(p);
+}
 
 static int ptrace_trapping_sleep_fn(void *flags)
 {
@@ -106,7 +118,7 @@ void __ptrace_unlink(struct task_struct *child)
         * TASK_KILLABLE sleeps.
         */
        if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child))
-               signal_wake_up(child, task_is_traced(child));
+               ptrace_signal_wake_up(child, task_is_traced(child));
 
        spin_unlock(&child->sighand->siglock);
 }
@@ -296,7 +308,7 @@ static int ptrace_attach(struct task_struct *task, long 
request,
         */
        if (task_is_stopped(task) &&
            task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING))
-               signal_wake_up(task, 1);
+               ptrace_signal_wake_up(task, 1);
 
        spin_unlock(&task->sighand->siglock);
 
@@ -731,7 +743,7 @@ int ptrace_request(struct task_struct *child, long request,
                 * tracee into STOP.
                 */
                if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP)))
-                       signal_wake_up(child, child->jobctl & JOBCTL_LISTENING);
+                       ptrace_signal_wake_up(child, child->jobctl & 
JOBCTL_LISTENING);
 
                unlock_task_sighand(child, &flags);
                ret = 0;
@@ -760,7 +772,7 @@ int ptrace_request(struct task_struct *child, long request,
                 * of this trap and now.  Trigger re-trap immediately.
                 */
                if (child->jobctl & JOBCTL_TRAP_NOTIFY)
-                       signal_wake_up(child, true);
+                       ptrace_signal_wake_up(child, true);
 
                unlock_task_sighand(child, &flags);
                ret = 0;
diff --git a/kernel/signal.c b/kernel/signal.c
index 3e8e0b1..0dc6abb 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -854,7 +854,7 @@ static void ptrace_trap_notify(struct task_struct *t)
        assert_spin_locked(&t->sighand->siglock);
 
        task_set_jobctl_pending(t, JOBCTL_TRAP_NOTIFY);
-       signal_wake_up(t, t->jobctl & JOBCTL_LISTENING);
+       ptrace_signal_wake_up(t, t->jobctl & JOBCTL_LISTENING);
 }
 
 /*
-- 
1.5.5.1


Reply via email to