aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2008-07-25 22:45:47 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-26 15:00:08 -0400
commit09a05394fe2448a4139b014936330af23fa7ec83 (patch)
treea7b3f0ffe271d4d35c3b98a99183d8792ea4db53
parent30199f5a46aee204bf437a4f5b0740f3efe448b7 (diff)
tracehook: clone
This moves all the ptrace initialization and tracing logic for task creation into tracehook.h and ptrace.h inlines. It reorganizes the code slightly, but should not change any behavior. There are four tracehook entry points, at each important stage of task creation. This keeps the interface from the core fork.c code fairly clean, while supporting the complex setup required for ptrace or something like it. Signed-off-by: Roland McGrath <roland@redhat.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Reviewed-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/ptrace.h22
-rw-r--r--include/linux/tracehook.h100
-rw-r--r--kernel/fork.c69
3 files changed, 150 insertions, 41 deletions
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index c74abfc4c7e8..dae6d85520fb 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -154,6 +154,28 @@ static inline int ptrace_event(int mask, int event, unsigned long message)
154 return 1; 154 return 1;
155} 155}
156 156
157/**
158 * ptrace_init_task - initialize ptrace state for a new child
159 * @child: new child task
160 * @ptrace: true if child should be ptrace'd by parent's tracer
161 *
162 * This is called immediately after adding @child to its parent's children
163 * list. @ptrace is false in the normal case, and true to ptrace @child.
164 *
165 * Called with current's siglock and write_lock_irq(&tasklist_lock) held.
166 */
167static inline void ptrace_init_task(struct task_struct *child, bool ptrace)
168{
169 INIT_LIST_HEAD(&child->ptrace_entry);
170 INIT_LIST_HEAD(&child->ptraced);
171 child->parent = child->real_parent;
172 child->ptrace = 0;
173 if (unlikely(ptrace)) {
174 child->ptrace = current->ptrace;
175 __ptrace_link(child, current->parent);
176 }
177}
178
157#ifndef force_successful_syscall_return 179#ifndef force_successful_syscall_return
158/* 180/*
159 * System call handlers that, upon successful completion, need to return a 181 * System call handlers that, upon successful completion, need to return a
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h
index 967ab473afbc..3ebc58b59766 100644
--- a/include/linux/tracehook.h
+++ b/include/linux/tracehook.h
@@ -110,4 +110,104 @@ static inline void tracehook_report_exit(long *exit_code)
110 ptrace_event(PT_TRACE_EXIT, PTRACE_EVENT_EXIT, *exit_code); 110 ptrace_event(PT_TRACE_EXIT, PTRACE_EVENT_EXIT, *exit_code);
111} 111}
112 112
113/**
114 * tracehook_prepare_clone - prepare for new child to be cloned
115 * @clone_flags: %CLONE_* flags from clone/fork/vfork system call
116 *
117 * This is called before a new user task is to be cloned.
118 * Its return value will be passed to tracehook_finish_clone().
119 *
120 * Called with no locks held.
121 */
122static inline int tracehook_prepare_clone(unsigned clone_flags)
123{
124 if (clone_flags & CLONE_UNTRACED)
125 return 0;
126
127 if (clone_flags & CLONE_VFORK) {
128 if (current->ptrace & PT_TRACE_VFORK)
129 return PTRACE_EVENT_VFORK;
130 } else if ((clone_flags & CSIGNAL) != SIGCHLD) {
131 if (current->ptrace & PT_TRACE_CLONE)
132 return PTRACE_EVENT_CLONE;
133 } else if (current->ptrace & PT_TRACE_FORK)
134 return PTRACE_EVENT_FORK;
135
136 return 0;
137}
138
139/**
140 * tracehook_finish_clone - new child created and being attached
141 * @child: new child task
142 * @clone_flags: %CLONE_* flags from clone/fork/vfork system call
143 * @trace: return value from tracehook_clone_prepare()
144 *
145 * This is called immediately after adding @child to its parent's children list.
146 * The @trace value is that returned by tracehook_prepare_clone().
147 *
148 * Called with current's siglock and write_lock_irq(&tasklist_lock) held.
149 */
150static inline void tracehook_finish_clone(struct task_struct *child,
151 unsigned long clone_flags, int trace)
152{
153 ptrace_init_task(child, (clone_flags & CLONE_PTRACE) || trace);
154}
155
156/**
157 * tracehook_report_clone - in parent, new child is about to start running
158 * @trace: return value from tracehook_clone_prepare()
159 * @regs: parent's user register state
160 * @clone_flags: flags from parent's system call
161 * @pid: new child's PID in the parent's namespace
162 * @child: new child task
163 *
164 * Called after a child is set up, but before it has been started running.
165 * The @trace value is that returned by tracehook_clone_prepare().
166 * This is not a good place to block, because the child has not started yet.
167 * Suspend the child here if desired, and block in tracehook_clone_complete().
168 * This must prevent the child from self-reaping if tracehook_clone_complete()
169 * uses the @child pointer; otherwise it might have died and been released by
170 * the time tracehook_report_clone_complete() is called.
171 *
172 * Called with no locks held, but the child cannot run until this returns.
173 */
174static inline void tracehook_report_clone(int trace, struct pt_regs *regs,
175 unsigned long clone_flags,
176 pid_t pid, struct task_struct *child)
177{
178 if (unlikely(trace)) {
179 /*
180 * The child starts up with an immediate SIGSTOP.
181 */
182 sigaddset(&child->pending.signal, SIGSTOP);
183 set_tsk_thread_flag(child, TIF_SIGPENDING);
184 }
185}
186
187/**
188 * tracehook_report_clone_complete - new child is running
189 * @trace: return value from tracehook_clone_prepare()
190 * @regs: parent's user register state
191 * @clone_flags: flags from parent's system call
192 * @pid: new child's PID in the parent's namespace
193 * @child: child task, already running
194 *
195 * This is called just after the child has started running. This is
196 * just before the clone/fork syscall returns, or blocks for vfork
197 * child completion if @clone_flags has the %CLONE_VFORK bit set.
198 * The @child pointer may be invalid if a self-reaping child died and
199 * tracehook_report_clone() took no action to prevent it from self-reaping.
200 *
201 * Called with no locks held.
202 */
203static inline void tracehook_report_clone_complete(int trace,
204 struct pt_regs *regs,
205 unsigned long clone_flags,
206 pid_t pid,
207 struct task_struct *child)
208{
209 if (unlikely(trace))
210 ptrace_event(0, trace, pid);
211}
212
113#endif /* <linux/tracehook.h> */ 213#endif /* <linux/tracehook.h> */
diff --git a/kernel/fork.c b/kernel/fork.c
index 80e83e459b17..b42f8ed23611 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -37,6 +37,7 @@
37#include <linux/swap.h> 37#include <linux/swap.h>
38#include <linux/syscalls.h> 38#include <linux/syscalls.h>
39#include <linux/jiffies.h> 39#include <linux/jiffies.h>
40#include <linux/tracehook.h>
40#include <linux/futex.h> 41#include <linux/futex.h>
41#include <linux/task_io_accounting_ops.h> 42#include <linux/task_io_accounting_ops.h>
42#include <linux/rcupdate.h> 43#include <linux/rcupdate.h>
@@ -865,8 +866,7 @@ static void copy_flags(unsigned long clone_flags, struct task_struct *p)
865 866
866 new_flags &= ~PF_SUPERPRIV; 867 new_flags &= ~PF_SUPERPRIV;
867 new_flags |= PF_FORKNOEXEC; 868 new_flags |= PF_FORKNOEXEC;
868 if (!(clone_flags & CLONE_PTRACE)) 869 new_flags |= PF_STARTING;
869 p->ptrace = 0;
870 p->flags = new_flags; 870 p->flags = new_flags;
871 clear_freeze_flag(p); 871 clear_freeze_flag(p);
872} 872}
@@ -907,7 +907,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
907 struct pt_regs *regs, 907 struct pt_regs *regs,
908 unsigned long stack_size, 908 unsigned long stack_size,
909 int __user *child_tidptr, 909 int __user *child_tidptr,
910 struct pid *pid) 910 struct pid *pid,
911 int trace)
911{ 912{
912 int retval; 913 int retval;
913 struct task_struct *p; 914 struct task_struct *p;
@@ -1163,8 +1164,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1163 */ 1164 */
1164 p->group_leader = p; 1165 p->group_leader = p;
1165 INIT_LIST_HEAD(&p->thread_group); 1166 INIT_LIST_HEAD(&p->thread_group);
1166 INIT_LIST_HEAD(&p->ptrace_entry);
1167 INIT_LIST_HEAD(&p->ptraced);
1168 1167
1169 /* Now that the task is set up, run cgroup callbacks if 1168 /* Now that the task is set up, run cgroup callbacks if
1170 * necessary. We need to run them before the task is visible 1169 * necessary. We need to run them before the task is visible
@@ -1195,7 +1194,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1195 p->real_parent = current->real_parent; 1194 p->real_parent = current->real_parent;
1196 else 1195 else
1197 p->real_parent = current; 1196 p->real_parent = current;
1198 p->parent = p->real_parent;
1199 1197
1200 spin_lock(&current->sighand->siglock); 1198 spin_lock(&current->sighand->siglock);
1201 1199
@@ -1237,8 +1235,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1237 1235
1238 if (likely(p->pid)) { 1236 if (likely(p->pid)) {
1239 list_add_tail(&p->sibling, &p->real_parent->children); 1237 list_add_tail(&p->sibling, &p->real_parent->children);
1240 if (unlikely(p->ptrace & PT_PTRACED)) 1238 tracehook_finish_clone(p, clone_flags, trace);
1241 __ptrace_link(p, current->parent);
1242 1239
1243 if (thread_group_leader(p)) { 1240 if (thread_group_leader(p)) {
1244 if (clone_flags & CLONE_NEWPID) 1241 if (clone_flags & CLONE_NEWPID)
@@ -1323,29 +1320,13 @@ struct task_struct * __cpuinit fork_idle(int cpu)
1323 struct pt_regs regs; 1320 struct pt_regs regs;
1324 1321
1325 task = copy_process(CLONE_VM, 0, idle_regs(&regs), 0, NULL, 1322 task = copy_process(CLONE_VM, 0, idle_regs(&regs), 0, NULL,
1326 &init_struct_pid); 1323 &init_struct_pid, 0);
1327 if (!IS_ERR(task)) 1324 if (!IS_ERR(task))
1328 init_idle(task, cpu); 1325 init_idle(task, cpu);
1329 1326
1330 return task; 1327 return task;
1331} 1328}
1332 1329
1333static int fork_traceflag(unsigned clone_flags)
1334{
1335 if (clone_flags & CLONE_UNTRACED)
1336 return 0;
1337 else if (clone_flags & CLONE_VFORK) {
1338 if (current->ptrace & PT_TRACE_VFORK)
1339 return PTRACE_EVENT_VFORK;
1340 } else if ((clone_flags & CSIGNAL) != SIGCHLD) {
1341 if (current->ptrace & PT_TRACE_CLONE)
1342 return PTRACE_EVENT_CLONE;
1343 } else if (current->ptrace & PT_TRACE_FORK)
1344 return PTRACE_EVENT_FORK;
1345
1346 return 0;
1347}
1348
1349/* 1330/*
1350 * Ok, this is the main fork-routine. 1331 * Ok, this is the main fork-routine.
1351 * 1332 *
@@ -1380,14 +1361,14 @@ long do_fork(unsigned long clone_flags,
1380 } 1361 }
1381 } 1362 }
1382 1363
1383 if (unlikely(current->ptrace)) { 1364 /*
1384 trace = fork_traceflag (clone_flags); 1365 * When called from kernel_thread, don't do user tracing stuff.
1385 if (trace) 1366 */
1386 clone_flags |= CLONE_PTRACE; 1367 if (likely(user_mode(regs)))
1387 } 1368 trace = tracehook_prepare_clone(clone_flags);
1388 1369
1389 p = copy_process(clone_flags, stack_start, regs, stack_size, 1370 p = copy_process(clone_flags, stack_start, regs, stack_size,
1390 child_tidptr, NULL); 1371 child_tidptr, NULL, trace);
1391 /* 1372 /*
1392 * Do this prior waking up the new thread - the thread pointer 1373 * Do this prior waking up the new thread - the thread pointer
1393 * might get invalid after that point, if the thread exits quickly. 1374 * might get invalid after that point, if the thread exits quickly.
@@ -1405,24 +1386,30 @@ long do_fork(unsigned long clone_flags,
1405 init_completion(&vfork); 1386 init_completion(&vfork);
1406 } 1387 }
1407 1388
1408 if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) { 1389 tracehook_report_clone(trace, regs, clone_flags, nr, p);
1390
1391 /*
1392 * We set PF_STARTING at creation in case tracing wants to
1393 * use this to distinguish a fully live task from one that
1394 * hasn't gotten to tracehook_report_clone() yet. Now we
1395 * clear it and set the child going.
1396 */
1397 p->flags &= ~PF_STARTING;
1398
1399 if (unlikely(clone_flags & CLONE_STOPPED)) {
1409 /* 1400 /*
1410 * We'll start up with an immediate SIGSTOP. 1401 * We'll start up with an immediate SIGSTOP.
1411 */ 1402 */
1412 sigaddset(&p->pending.signal, SIGSTOP); 1403 sigaddset(&p->pending.signal, SIGSTOP);
1413 set_tsk_thread_flag(p, TIF_SIGPENDING); 1404 set_tsk_thread_flag(p, TIF_SIGPENDING);
1414 }
1415
1416 if (!(clone_flags & CLONE_STOPPED))
1417 wake_up_new_task(p, clone_flags);
1418 else
1419 __set_task_state(p, TASK_STOPPED); 1405 __set_task_state(p, TASK_STOPPED);
1420 1406 } else {
1421 if (unlikely (trace)) { 1407 wake_up_new_task(p, clone_flags);
1422 current->ptrace_message = nr;
1423 ptrace_notify ((trace << 8) | SIGTRAP);
1424 } 1408 }
1425 1409
1410 tracehook_report_clone_complete(trace, regs,
1411 clone_flags, nr, p);
1412
1426 if (clone_flags & CLONE_VFORK) { 1413 if (clone_flags & CLONE_VFORK) {
1427 freezer_do_not_count(); 1414 freezer_do_not_count();
1428 wait_for_completion(&vfork); 1415 wait_for_completion(&vfork);