diff options
-rw-r--r-- | include/linux/ptrace.h | 22 | ||||
-rw-r--r-- | include/linux/tracehook.h | 100 | ||||
-rw-r--r-- | kernel/fork.c | 69 |
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 | */ | ||
167 | static 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 | */ | ||
122 | static 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 | */ | ||
150 | static 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 | */ | ||
174 | static 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 | */ | ||
203 | static 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(¤t->sighand->siglock); | 1198 | spin_lock(¤t->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(®s), 0, NULL, | 1322 | task = copy_process(CLONE_VM, 0, idle_regs(®s), 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 | ||
1333 | static 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); |