aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);