@@ -37,35 +37,33 @@ void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
37
37
child -> parent = new_parent ;
38
38
}
39
39
40
- /*
41
- * Turn a tracing stop into a normal stop now, since with no tracer there
42
- * would be no way to wake it up with SIGCONT or SIGKILL. If there was a
43
- * signal sent that would resume the child, but didn't because it was in
44
- * TASK_TRACED, resume it now.
45
- * Requires that irqs be disabled.
46
- */
47
- static void ptrace_untrace (struct task_struct * child )
48
- {
49
- spin_lock (& child -> sighand -> siglock );
50
- if (task_is_traced (child )) {
51
- /*
52
- * If the group stop is completed or in progress,
53
- * this thread was already counted as stopped.
54
- */
55
- if (child -> signal -> flags & SIGNAL_STOP_STOPPED ||
56
- child -> signal -> group_stop_count )
57
- __set_task_state (child , TASK_STOPPED );
58
- else
59
- signal_wake_up (child , 1 );
60
- }
61
- spin_unlock (& child -> sighand -> siglock );
62
- }
63
-
64
- /*
65
- * unptrace a task: move it back to its original parent and
66
- * remove it from the ptrace list.
40
+ /**
41
+ * __ptrace_unlink - unlink ptracee and restore its execution state
42
+ * @child: ptracee to be unlinked
67
43
*
68
- * Must be called with the tasklist lock write-held.
44
+ * Remove @child from the ptrace list, move it back to the original parent,
45
+ * and restore the execution state so that it conforms to the group stop
46
+ * state.
47
+ *
48
+ * Unlinking can happen via two paths - explicit PTRACE_DETACH or ptracer
49
+ * exiting. For PTRACE_DETACH, unless the ptracee has been killed between
50
+ * ptrace_check_attach() and here, it's guaranteed to be in TASK_TRACED.
51
+ * If the ptracer is exiting, the ptracee can be in any state.
52
+ *
53
+ * After detach, the ptracee should be in a state which conforms to the
54
+ * group stop. If the group is stopped or in the process of stopping, the
55
+ * ptracee should be put into TASK_STOPPED; otherwise, it should be woken
56
+ * up from TASK_TRACED.
57
+ *
58
+ * If the ptracee is in TASK_TRACED and needs to be moved to TASK_STOPPED,
59
+ * it goes through TRACED -> RUNNING -> STOPPED transition which is similar
60
+ * to but in the opposite direction of what happens while attaching to a
61
+ * stopped task. However, in this direction, the intermediate RUNNING
62
+ * state is not hidden even from the current ptracer and if it immediately
63
+ * re-attaches and performs a WNOHANG wait(2), it may fail.
64
+ *
65
+ * CONTEXT:
66
+ * write_lock_irq(tasklist_lock)
69
67
*/
70
68
void __ptrace_unlink (struct task_struct * child )
71
69
{
@@ -75,8 +73,27 @@ void __ptrace_unlink(struct task_struct *child)
75
73
child -> parent = child -> real_parent ;
76
74
list_del_init (& child -> ptrace_entry );
77
75
78
- if (task_is_traced (child ))
79
- ptrace_untrace (child );
76
+ spin_lock (& child -> sighand -> siglock );
77
+
78
+ /*
79
+ * Reinstate GROUP_STOP_PENDING if group stop is in effect and
80
+ * @child isn't dead.
81
+ */
82
+ if (!(child -> flags & PF_EXITING ) &&
83
+ (child -> signal -> flags & SIGNAL_STOP_STOPPED ||
84
+ child -> signal -> group_stop_count ))
85
+ child -> group_stop |= GROUP_STOP_PENDING ;
86
+
87
+ /*
88
+ * If transition to TASK_STOPPED is pending or in TASK_TRACED, kick
89
+ * @child in the butt. Note that @resume should be used iff @child
90
+ * is in TASK_TRACED; otherwise, we might unduly disrupt
91
+ * TASK_KILLABLE sleeps.
92
+ */
93
+ if (child -> group_stop & GROUP_STOP_PENDING || task_is_traced (child ))
94
+ signal_wake_up (child , task_is_traced (child ));
95
+
96
+ spin_unlock (& child -> sighand -> siglock );
80
97
}
81
98
82
99
/*
@@ -95,16 +112,14 @@ int ptrace_check_attach(struct task_struct *child, int kill)
95
112
*/
96
113
read_lock (& tasklist_lock );
97
114
if ((child -> ptrace & PT_PTRACED ) && child -> parent == current ) {
98
- ret = 0 ;
99
115
/*
100
116
* child->sighand can't be NULL, release_task()
101
117
* does ptrace_unlink() before __exit_signal().
102
118
*/
103
119
spin_lock_irq (& child -> sighand -> siglock );
104
- if (task_is_stopped (child ))
105
- child -> state = TASK_TRACED ;
106
- else if (!task_is_traced (child ) && !kill )
107
- ret = - ESRCH ;
120
+ WARN_ON_ONCE (task_is_stopped (child ));
121
+ if (task_is_traced (child ) || kill )
122
+ ret = 0 ;
108
123
spin_unlock_irq (& child -> sighand -> siglock );
109
124
}
110
125
read_unlock (& tasklist_lock );
@@ -168,6 +183,7 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
168
183
169
184
static int ptrace_attach (struct task_struct * task )
170
185
{
186
+ bool wait_trap = false;
171
187
int retval ;
172
188
173
189
audit_ptrace (task );
@@ -207,12 +223,42 @@ static int ptrace_attach(struct task_struct *task)
207
223
__ptrace_link (task , current );
208
224
send_sig_info (SIGSTOP , SEND_SIG_FORCED , task );
209
225
226
+ spin_lock (& task -> sighand -> siglock );
227
+
228
+ /*
229
+ * If the task is already STOPPED, set GROUP_STOP_PENDING and
230
+ * TRAPPING, and kick it so that it transits to TRACED. TRAPPING
231
+ * will be cleared if the child completes the transition or any
232
+ * event which clears the group stop states happens. We'll wait
233
+ * for the transition to complete before returning from this
234
+ * function.
235
+ *
236
+ * This hides STOPPED -> RUNNING -> TRACED transition from the
237
+ * attaching thread but a different thread in the same group can
238
+ * still observe the transient RUNNING state. IOW, if another
239
+ * thread's WNOHANG wait(2) on the stopped tracee races against
240
+ * ATTACH, the wait(2) may fail due to the transient RUNNING.
241
+ *
242
+ * The following task_is_stopped() test is safe as both transitions
243
+ * in and out of STOPPED are protected by siglock.
244
+ */
245
+ if (task_is_stopped (task )) {
246
+ task -> group_stop |= GROUP_STOP_PENDING | GROUP_STOP_TRAPPING ;
247
+ signal_wake_up (task , 1 );
248
+ wait_trap = true;
249
+ }
250
+
251
+ spin_unlock (& task -> sighand -> siglock );
252
+
210
253
retval = 0 ;
211
254
unlock_tasklist :
212
255
write_unlock_irq (& tasklist_lock );
213
256
unlock_creds :
214
257
mutex_unlock (& task -> signal -> cred_guard_mutex );
215
258
out :
259
+ if (wait_trap )
260
+ wait_event (current -> signal -> wait_chldexit ,
261
+ !(task -> group_stop & GROUP_STOP_TRAPPING ));
216
262
return retval ;
217
263
}
218
264
@@ -315,8 +361,6 @@ static int ptrace_detach(struct task_struct *child, unsigned int data)
315
361
if (child -> ptrace ) {
316
362
child -> exit_code = data ;
317
363
dead = __ptrace_detach (current , child );
318
- if (!child -> exit_state )
319
- wake_up_state (child , TASK_TRACED | TASK_STOPPED );
320
364
}
321
365
write_unlock_irq (& tasklist_lock );
322
366
0 commit comments