diff options
-rw-r--r-- | include/linux/ptrace.h | 13 | ||||
-rw-r--r-- | include/linux/tracehook.h | 28 | ||||
-rw-r--r-- | kernel/exit.c | 21 |
3 files changed, 50 insertions, 12 deletions
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index dae6d85520fb..ed69c03692d9 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
@@ -176,6 +176,19 @@ static inline void ptrace_init_task(struct task_struct *child, bool ptrace) | |||
176 | } | 176 | } |
177 | } | 177 | } |
178 | 178 | ||
179 | /** | ||
180 | * ptrace_release_task - final ptrace-related cleanup of a zombie being reaped | ||
181 | * @task: task in %EXIT_DEAD state | ||
182 | * | ||
183 | * Called with write_lock(&tasklist_lock) held. | ||
184 | */ | ||
185 | static inline void ptrace_release_task(struct task_struct *task) | ||
186 | { | ||
187 | BUG_ON(!list_empty(&task->ptraced)); | ||
188 | ptrace_unlink(task); | ||
189 | BUG_ON(!list_empty(&task->ptrace_entry)); | ||
190 | } | ||
191 | |||
179 | #ifndef force_successful_syscall_return | 192 | #ifndef force_successful_syscall_return |
180 | /* | 193 | /* |
181 | * System call handlers that, upon successful completion, need to return a | 194 | * System call handlers that, upon successful completion, need to return a |
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h index 830e6e16097d..9a5b3be2503a 100644 --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h | |||
@@ -228,4 +228,32 @@ static inline void tracehook_report_vfork_done(struct task_struct *child, | |||
228 | ptrace_event(PT_TRACE_VFORK_DONE, PTRACE_EVENT_VFORK_DONE, pid); | 228 | ptrace_event(PT_TRACE_VFORK_DONE, PTRACE_EVENT_VFORK_DONE, pid); |
229 | } | 229 | } |
230 | 230 | ||
231 | /** | ||
232 | * tracehook_prepare_release_task - task is being reaped, clean up tracing | ||
233 | * @task: task in %EXIT_DEAD state | ||
234 | * | ||
235 | * This is called in release_task() just before @task gets finally reaped | ||
236 | * and freed. This would be the ideal place to remove and clean up any | ||
237 | * tracing-related state for @task. | ||
238 | * | ||
239 | * Called with no locks held. | ||
240 | */ | ||
241 | static inline void tracehook_prepare_release_task(struct task_struct *task) | ||
242 | { | ||
243 | } | ||
244 | |||
245 | /** | ||
246 | * tracehook_finish_release_task - task is being reaped, clean up tracing | ||
247 | * @task: task in %EXIT_DEAD state | ||
248 | * | ||
249 | * This is called in release_task() when @task is being in the middle of | ||
250 | * being reaped. After this, there must be no tracing entanglements. | ||
251 | * | ||
252 | * Called with write_lock_irq(&tasklist_lock) held. | ||
253 | */ | ||
254 | static inline void tracehook_finish_release_task(struct task_struct *task) | ||
255 | { | ||
256 | ptrace_release_task(task); | ||
257 | } | ||
258 | |||
231 | #endif /* <linux/tracehook.h> */ | 259 | #endif /* <linux/tracehook.h> */ |
diff --git a/kernel/exit.c b/kernel/exit.c index c3691cbc220a..da28745f7c38 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -163,27 +163,17 @@ static void delayed_put_task_struct(struct rcu_head *rhp) | |||
163 | put_task_struct(container_of(rhp, struct task_struct, rcu)); | 163 | put_task_struct(container_of(rhp, struct task_struct, rcu)); |
164 | } | 164 | } |
165 | 165 | ||
166 | /* | ||
167 | * Do final ptrace-related cleanup of a zombie being reaped. | ||
168 | * | ||
169 | * Called with write_lock(&tasklist_lock) held. | ||
170 | */ | ||
171 | static void ptrace_release_task(struct task_struct *p) | ||
172 | { | ||
173 | BUG_ON(!list_empty(&p->ptraced)); | ||
174 | ptrace_unlink(p); | ||
175 | BUG_ON(!list_empty(&p->ptrace_entry)); | ||
176 | } | ||
177 | 166 | ||
178 | void release_task(struct task_struct * p) | 167 | void release_task(struct task_struct * p) |
179 | { | 168 | { |
180 | struct task_struct *leader; | 169 | struct task_struct *leader; |
181 | int zap_leader; | 170 | int zap_leader; |
182 | repeat: | 171 | repeat: |
172 | tracehook_prepare_release_task(p); | ||
183 | atomic_dec(&p->user->processes); | 173 | atomic_dec(&p->user->processes); |
184 | proc_flush_task(p); | 174 | proc_flush_task(p); |
185 | write_lock_irq(&tasklist_lock); | 175 | write_lock_irq(&tasklist_lock); |
186 | ptrace_release_task(p); | 176 | tracehook_finish_release_task(p); |
187 | __exit_signal(p); | 177 | __exit_signal(p); |
188 | 178 | ||
189 | /* | 179 | /* |
@@ -205,6 +195,13 @@ repeat: | |||
205 | * that case. | 195 | * that case. |
206 | */ | 196 | */ |
207 | zap_leader = task_detached(leader); | 197 | zap_leader = task_detached(leader); |
198 | |||
199 | /* | ||
200 | * This maintains the invariant that release_task() | ||
201 | * only runs on a task in EXIT_DEAD, just for sanity. | ||
202 | */ | ||
203 | if (zap_leader) | ||
204 | leader->exit_state = EXIT_DEAD; | ||
208 | } | 205 | } |
209 | 206 | ||
210 | write_unlock_irq(&tasklist_lock); | 207 | write_unlock_irq(&tasklist_lock); |