Skip to content

Commit e46bc9b

Browse files
committed
Merge branch 'ptrace' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/misc into ptrace
2 parents 2b9accb + 321fb56 commit e46bc9b

File tree

6 files changed

+442
-180
lines changed

6 files changed

+442
-180
lines changed

fs/exec.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,6 +1659,7 @@ static int zap_process(struct task_struct *start, int exit_code)
16591659

16601660
t = start;
16611661
do {
1662+
task_clear_group_stop_pending(t);
16621663
if (t != current && t->mm) {
16631664
sigaddset(&t->pending.signal, SIGKILL);
16641665
signal_wake_up(t, 1);

include/linux/sched.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -653,9 +653,8 @@ struct signal_struct {
653653
* Bits in flags field of signal_struct.
654654
*/
655655
#define SIGNAL_STOP_STOPPED 0x00000001 /* job control stop in effect */
656-
#define SIGNAL_STOP_DEQUEUED 0x00000002 /* stop signal dequeued */
657-
#define SIGNAL_STOP_CONTINUED 0x00000004 /* SIGCONT since WCONTINUED reap */
658-
#define SIGNAL_GROUP_EXIT 0x00000008 /* group exit in progress */
656+
#define SIGNAL_STOP_CONTINUED 0x00000002 /* SIGCONT since WCONTINUED reap */
657+
#define SIGNAL_GROUP_EXIT 0x00000004 /* group exit in progress */
659658
/*
660659
* Pending notifications to parent.
661660
*/
@@ -1261,6 +1260,7 @@ struct task_struct {
12611260
int exit_state;
12621261
int exit_code, exit_signal;
12631262
int pdeath_signal; /* The signal sent when the parent dies */
1263+
unsigned int group_stop; /* GROUP_STOP_*, siglock protected */
12641264
/* ??? */
12651265
unsigned int personality;
12661266
unsigned did_exec:1;
@@ -1777,6 +1777,17 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
17771777
#define tsk_used_math(p) ((p)->flags & PF_USED_MATH)
17781778
#define used_math() tsk_used_math(current)
17791779

1780+
/*
1781+
* task->group_stop flags
1782+
*/
1783+
#define GROUP_STOP_SIGMASK 0xffff /* signr of the last group stop */
1784+
#define GROUP_STOP_PENDING (1 << 16) /* task should stop for group stop */
1785+
#define GROUP_STOP_CONSUME (1 << 17) /* consume group stop count */
1786+
#define GROUP_STOP_TRAPPING (1 << 18) /* switching from STOPPED to TRACED */
1787+
#define GROUP_STOP_DEQUEUED (1 << 19) /* stop signal dequeued */
1788+
1789+
extern void task_clear_group_stop_pending(struct task_struct *task);
1790+
17801791
#ifdef CONFIG_PREEMPT_RCU
17811792

17821793
#define RCU_READ_UNLOCK_BLOCKED (1 << 0) /* blocked while in RCU read-side. */

include/linux/tracehook.h

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -468,33 +468,6 @@ static inline int tracehook_get_signal(struct task_struct *task,
468468
return 0;
469469
}
470470

471-
/**
472-
* tracehook_notify_jctl - report about job control stop/continue
473-
* @notify: zero, %CLD_STOPPED or %CLD_CONTINUED
474-
* @why: %CLD_STOPPED or %CLD_CONTINUED
475-
*
476-
* This is called when we might call do_notify_parent_cldstop().
477-
*
478-
* @notify is zero if we would not ordinarily send a %SIGCHLD,
479-
* or is the %CLD_STOPPED or %CLD_CONTINUED .si_code for %SIGCHLD.
480-
*
481-
* @why is %CLD_STOPPED when about to stop for job control;
482-
* we are already in %TASK_STOPPED state, about to call schedule().
483-
* It might also be that we have just exited (check %PF_EXITING),
484-
* but need to report that a group-wide stop is complete.
485-
*
486-
* @why is %CLD_CONTINUED when waking up after job control stop and
487-
* ready to make a delayed @notify report.
488-
*
489-
* Return the %CLD_* value for %SIGCHLD, or zero to generate no signal.
490-
*
491-
* Called with the siglock held.
492-
*/
493-
static inline int tracehook_notify_jctl(int notify, int why)
494-
{
495-
return notify ?: (current->ptrace & PT_PTRACED) ? why : 0;
496-
}
497-
498471
/**
499472
* tracehook_finish_jctl - report about return from job control stop
500473
*

kernel/exit.c

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,33 +1538,83 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace,
15381538
return 0;
15391539
}
15401540

1541-
if (likely(!ptrace) && unlikely(task_ptrace(p))) {
1541+
/* dead body doesn't have much to contribute */
1542+
if (p->exit_state == EXIT_DEAD)
1543+
return 0;
1544+
1545+
/* slay zombie? */
1546+
if (p->exit_state == EXIT_ZOMBIE) {
15421547
/*
1543-
* This child is hidden by ptrace.
1544-
* We aren't allowed to see it now, but eventually we will.
1548+
* A zombie ptracee is only visible to its ptracer.
1549+
* Notification and reaping will be cascaded to the real
1550+
* parent when the ptracer detaches.
15451551
*/
1546-
wo->notask_error = 0;
1547-
return 0;
1548-
}
1552+
if (likely(!ptrace) && unlikely(task_ptrace(p))) {
1553+
/* it will become visible, clear notask_error */
1554+
wo->notask_error = 0;
1555+
return 0;
1556+
}
15491557

1550-
if (p->exit_state == EXIT_DEAD)
1551-
return 0;
1558+
/* we don't reap group leaders with subthreads */
1559+
if (!delay_group_leader(p))
1560+
return wait_task_zombie(wo, p);
15521561

1553-
/*
1554-
* We don't reap group leaders with subthreads.
1555-
*/
1556-
if (p->exit_state == EXIT_ZOMBIE && !delay_group_leader(p))
1557-
return wait_task_zombie(wo, p);
1562+
/*
1563+
* Allow access to stopped/continued state via zombie by
1564+
* falling through. Clearing of notask_error is complex.
1565+
*
1566+
* When !@ptrace:
1567+
*
1568+
* If WEXITED is set, notask_error should naturally be
1569+
* cleared. If not, subset of WSTOPPED|WCONTINUED is set,
1570+
* so, if there are live subthreads, there are events to
1571+
* wait for. If all subthreads are dead, it's still safe
1572+
* to clear - this function will be called again in finite
1573+
* amount time once all the subthreads are released and
1574+
* will then return without clearing.
1575+
*
1576+
* When @ptrace:
1577+
*
1578+
* Stopped state is per-task and thus can't change once the
1579+
* target task dies. Only continued and exited can happen.
1580+
* Clear notask_error if WCONTINUED | WEXITED.
1581+
*/
1582+
if (likely(!ptrace) || (wo->wo_flags & (WCONTINUED | WEXITED)))
1583+
wo->notask_error = 0;
1584+
} else {
1585+
/*
1586+
* If @p is ptraced by a task in its real parent's group,
1587+
* hide group stop/continued state when looking at @p as
1588+
* the real parent; otherwise, a single stop can be
1589+
* reported twice as group and ptrace stops.
1590+
*
1591+
* If a ptracer wants to distinguish the two events for its
1592+
* own children, it should create a separate process which
1593+
* takes the role of real parent.
1594+
*/
1595+
if (likely(!ptrace) && task_ptrace(p) &&
1596+
same_thread_group(p->parent, p->real_parent))
1597+
return 0;
1598+
1599+
/*
1600+
* @p is alive and it's gonna stop, continue or exit, so
1601+
* there always is something to wait for.
1602+
*/
1603+
wo->notask_error = 0;
1604+
}
15581605

15591606
/*
1560-
* It's stopped or running now, so it might
1561-
* later continue, exit, or stop again.
1607+
* Wait for stopped. Depending on @ptrace, different stopped state
1608+
* is used and the two don't interact with each other.
15621609
*/
1563-
wo->notask_error = 0;
1564-
15651610
if (task_stopped_code(p, ptrace))
15661611
return wait_task_stopped(wo, ptrace, p);
15671612

1613+
/*
1614+
* Wait for continued. There's only one continued state and the
1615+
* ptracer can consume it which can confuse the real parent. Don't
1616+
* use WCONTINUED from ptracer. You don't need or want it.
1617+
*/
15681618
return wait_task_continued(wo, p);
15691619
}
15701620

kernel/ptrace.c

Lines changed: 81 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -37,35 +37,33 @@ void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
3737
child->parent = new_parent;
3838
}
3939

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
6743
*
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)
6967
*/
7068
void __ptrace_unlink(struct task_struct *child)
7169
{
@@ -75,8 +73,27 @@ void __ptrace_unlink(struct task_struct *child)
7573
child->parent = child->real_parent;
7674
list_del_init(&child->ptrace_entry);
7775

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);
8097
}
8198

8299
/*
@@ -95,16 +112,14 @@ int ptrace_check_attach(struct task_struct *child, int kill)
95112
*/
96113
read_lock(&tasklist_lock);
97114
if ((child->ptrace & PT_PTRACED) && child->parent == current) {
98-
ret = 0;
99115
/*
100116
* child->sighand can't be NULL, release_task()
101117
* does ptrace_unlink() before __exit_signal().
102118
*/
103119
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;
108123
spin_unlock_irq(&child->sighand->siglock);
109124
}
110125
read_unlock(&tasklist_lock);
@@ -168,6 +183,7 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
168183

169184
static int ptrace_attach(struct task_struct *task)
170185
{
186+
bool wait_trap = false;
171187
int retval;
172188

173189
audit_ptrace(task);
@@ -207,12 +223,42 @@ static int ptrace_attach(struct task_struct *task)
207223
__ptrace_link(task, current);
208224
send_sig_info(SIGSTOP, SEND_SIG_FORCED, task);
209225

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+
210253
retval = 0;
211254
unlock_tasklist:
212255
write_unlock_irq(&tasklist_lock);
213256
unlock_creds:
214257
mutex_unlock(&task->signal->cred_guard_mutex);
215258
out:
259+
if (wait_trap)
260+
wait_event(current->signal->wait_chldexit,
261+
!(task->group_stop & GROUP_STOP_TRAPPING));
216262
return retval;
217263
}
218264

@@ -315,8 +361,6 @@ static int ptrace_detach(struct task_struct *child, unsigned int data)
315361
if (child->ptrace) {
316362
child->exit_code = data;
317363
dead = __ptrace_detach(current, child);
318-
if (!child->exit_state)
319-
wake_up_state(child, TASK_TRACED | TASK_STOPPED);
320364
}
321365
write_unlock_irq(&tasklist_lock);
322366

0 commit comments

Comments
 (0)