aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/ptrace.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2011-04-07 14:44:11 -0400
committerOleg Nesterov <oleg@redhat.com>2011-04-07 14:44:11 -0400
commite46bc9b6fd65bc9f406a4211fbf95683cc9c2937 (patch)
tree57046f6b2f4674a0c9048ab1ad1ff50fae7e373a /kernel/ptrace.c
parent2b9accbee563f535046ff2cd382d0acaa92e130c (diff)
parent321fb561971ba0f10ce18c0f8a4b9fbfc7cef4b9 (diff)
Merge branch 'ptrace' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/misc into ptrace
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r--kernel/ptrace.c118
1 files changed, 81 insertions, 37 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 0fc1eed28d27..512bd017218d 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -37,35 +37,33 @@ void __ptrace_link(struct task_struct *child, struct task_struct *new_parent)
37 child->parent = new_parent; 37 child->parent = new_parent;
38} 38}
39 39
40/* 40/**
41 * Turn a tracing stop into a normal stop now, since with no tracer there 41 * __ptrace_unlink - unlink ptracee and restore its execution state
42 * would be no way to wake it up with SIGCONT or SIGKILL. If there was a 42 * @child: ptracee to be unlinked
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 */
47static 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.
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 */
70void __ptrace_unlink(struct task_struct *child) 68void __ptrace_unlink(struct task_struct *child)
71{ 69{
@@ -75,8 +73,27 @@ void __ptrace_unlink(struct task_struct *child)
75 child->parent = child->real_parent; 73 child->parent = child->real_parent;
76 list_del_init(&child->ptrace_entry); 74 list_del_init(&child->ptrace_entry);
77 75
78 if (task_is_traced(child)) 76 spin_lock(&child->sighand->siglock);
79 ptrace_untrace(child); 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 read_lock(&tasklist_lock); 113 read_lock(&tasklist_lock);
97 if ((child->ptrace & PT_PTRACED) && child->parent == current) { 114 if ((child->ptrace & PT_PTRACED) && child->parent == current) {
98 ret = 0;
99 /* 115 /*
100 * child->sighand can't be NULL, release_task() 116 * child->sighand can't be NULL, release_task()
101 * does ptrace_unlink() before __exit_signal(). 117 * does ptrace_unlink() before __exit_signal().
102 */ 118 */
103 spin_lock_irq(&child->sighand->siglock); 119 spin_lock_irq(&child->sighand->siglock);
104 if (task_is_stopped(child)) 120 WARN_ON_ONCE(task_is_stopped(child));
105 child->state = TASK_TRACED; 121 if (task_is_traced(child) || kill)
106 else if (!task_is_traced(child) && !kill) 122 ret = 0;
107 ret = -ESRCH;
108 spin_unlock_irq(&child->sighand->siglock); 123 spin_unlock_irq(&child->sighand->siglock);
109 } 124 }
110 read_unlock(&tasklist_lock); 125 read_unlock(&tasklist_lock);
@@ -168,6 +183,7 @@ bool ptrace_may_access(struct task_struct *task, unsigned int mode)
168 183
169static int ptrace_attach(struct task_struct *task) 184static int ptrace_attach(struct task_struct *task)
170{ 185{
186 bool wait_trap = false;
171 int retval; 187 int retval;
172 188
173 audit_ptrace(task); 189 audit_ptrace(task);
@@ -207,12 +223,42 @@ static int ptrace_attach(struct task_struct *task)
207 __ptrace_link(task, current); 223 __ptrace_link(task, current);
208 send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); 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 retval = 0; 253 retval = 0;
211unlock_tasklist: 254unlock_tasklist:
212 write_unlock_irq(&tasklist_lock); 255 write_unlock_irq(&tasklist_lock);
213unlock_creds: 256unlock_creds:
214 mutex_unlock(&task->signal->cred_guard_mutex); 257 mutex_unlock(&task->signal->cred_guard_mutex);
215out: 258out:
259 if (wait_trap)
260 wait_event(current->signal->wait_chldexit,
261 !(task->group_stop & GROUP_STOP_TRAPPING));
216 return retval; 262 return retval;
217} 263}
218 264
@@ -315,8 +361,6 @@ static int ptrace_detach(struct task_struct *child, unsigned int data)
315 if (child->ptrace) { 361 if (child->ptrace) {
316 child->exit_code = data; 362 child->exit_code = data;
317 dead = __ptrace_detach(current, child); 363 dead = __ptrace_detach(current, child);
318 if (!child->exit_state)
319 wake_up_state(child, TASK_TRACED | TASK_STOPPED);
320 } 364 }
321 write_unlock_irq(&tasklist_lock); 365 write_unlock_irq(&tasklist_lock);
322 366