aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/ptrace.c59
-rw-r--r--kernel/signal.c5
2 files changed, 55 insertions, 9 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index d77fa9eb082..40581ee5680 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -38,6 +38,36 @@ void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
38 child->parent = new_parent; 38 child->parent = new_parent;
39} 39}
40 40
41/* Ensure that nothing can wake it up, even SIGKILL */
42static bool ptrace_freeze_traced(struct task_struct *task)
43{
44 bool ret = false;
45
46 spin_lock_irq(&task->sighand->siglock);
47 if (task_is_traced(task) && !__fatal_signal_pending(task)) {
48 task->state = __TASK_TRACED;
49 ret = true;
50 }
51 spin_unlock_irq(&task->sighand->siglock);
52
53 return ret;
54}
55
56static void ptrace_unfreeze_traced(struct task_struct *task)
57{
58 if (task->state != __TASK_TRACED)
59 return;
60
61 WARN_ON(!task->ptrace || task->parent != current);
62
63 spin_lock_irq(&task->sighand->siglock);
64 if (__fatal_signal_pending(task))
65 wake_up_state(task, __TASK_TRACED);
66 else
67 task->state = TASK_TRACED;
68 spin_unlock_irq(&task->sighand->siglock);
69}
70
41/** 71/**
42 * __ptrace_unlink - unlink ptracee and restore its execution state 72 * __ptrace_unlink - unlink ptracee and restore its execution state
43 * @child: ptracee to be unlinked 73 * @child: ptracee to be unlinked
@@ -112,23 +142,29 @@ int ptrace_check_attach(struct task_struct *child, int kill)
112 * be changed by us so it's not changing right after this. 142 * be changed by us so it's not changing right after this.
113 */ 143 */
114 read_lock(&tasklist_lock); 144 read_lock(&tasklist_lock);
115 if ((child->ptrace & PT_PTRACED) && child->parent == current) { 145 if (child->ptrace && child->parent == current) {
146 WARN_ON(child->state == __TASK_TRACED);
116 /* 147 /*
117 * child->sighand can't be NULL, release_task() 148 * child->sighand can't be NULL, release_task()
118 * does ptrace_unlink() before __exit_signal(). 149 * does ptrace_unlink() before __exit_signal().
119 */ 150 */
120 spin_lock_irq(&child->sighand->siglock); 151 if (kill || ptrace_freeze_traced(child))
121 WARN_ON_ONCE(task_is_stopped(child));
122 if (task_is_traced(child) || kill)
123 ret = 0; 152 ret = 0;
124 spin_unlock_irq(&child->sighand->siglock);
125 } 153 }
126 read_unlock(&tasklist_lock); 154 read_unlock(&tasklist_lock);
127 155
128 if (!ret && !kill) 156 if (!ret && !kill) {
129 ret = wait_task_inactive(child, TASK_TRACED) ? 0 : -ESRCH; 157 if (!wait_task_inactive(child, __TASK_TRACED)) {
158 /*
159 * This can only happen if may_ptrace_stop() fails and
160 * ptrace_stop() changes ->state back to TASK_RUNNING,
161 * so we should not worry about leaking __TASK_TRACED.
162 */
163 WARN_ON(child->state == __TASK_TRACED);
164 ret = -ESRCH;
165 }
166 }
130 167
131 /* All systems go.. */
132 return ret; 168 return ret;
133} 169}
134 170
@@ -777,6 +813,8 @@ SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr,
777 goto out_put_task_struct; 813 goto out_put_task_struct;
778 814
779 ret = arch_ptrace(child, request, addr, data); 815 ret = arch_ptrace(child, request, addr, data);
816 if (ret || request != PTRACE_DETACH)
817 ptrace_unfreeze_traced(child);
780 818
781 out_put_task_struct: 819 out_put_task_struct:
782 put_task_struct(child); 820 put_task_struct(child);
@@ -915,8 +953,11 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
915 } 953 }
916 954
917 ret = ptrace_check_attach(child, request == PTRACE_KILL); 955 ret = ptrace_check_attach(child, request == PTRACE_KILL);
918 if (!ret) 956 if (!ret) {
919 ret = compat_arch_ptrace(child, request, addr, data); 957 ret = compat_arch_ptrace(child, request, addr, data);
958 if (ret || request != PTRACE_DETACH)
959 ptrace_unfreeze_traced(child);
960 }
920 961
921 out_put_task_struct: 962 out_put_task_struct:
922 put_task_struct(child); 963 put_task_struct(child);
diff --git a/kernel/signal.c b/kernel/signal.c
index 8b0dd5bb4da..51f2e694ec6 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1669,6 +1669,10 @@ static inline int may_ptrace_stop(void)
1669 * If SIGKILL was already sent before the caller unlocked 1669 * If SIGKILL was already sent before the caller unlocked
1670 * ->siglock we must see ->core_state != NULL. Otherwise it 1670 * ->siglock we must see ->core_state != NULL. Otherwise it
1671 * is safe to enter schedule(). 1671 * is safe to enter schedule().
1672 *
1673 * This is almost outdated, a task with the pending SIGKILL can't
1674 * block in TASK_TRACED. But PTRACE_EVENT_EXIT can be reported
1675 * after SIGKILL was already dequeued.
1672 */ 1676 */
1673 if (unlikely(current->mm->core_state) && 1677 if (unlikely(current->mm->core_state) &&
1674 unlikely(current->mm == current->parent->mm)) 1678 unlikely(current->mm == current->parent->mm))
@@ -1800,6 +1804,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
1800 if (gstop_done) 1804 if (gstop_done)
1801 do_notify_parent_cldstop(current, false, why); 1805 do_notify_parent_cldstop(current, false, why);
1802 1806
1807 /* tasklist protects us from ptrace_freeze_traced() */
1803 __set_current_state(TASK_RUNNING); 1808 __set_current_state(TASK_RUNNING);
1804 if (clear_code) 1809 if (clear_code)
1805 current->exit_code = 0; 1810 current->exit_code = 0;