aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ptrace.h13
-rw-r--r--include/linux/tracehook.h28
-rw-r--r--kernel/exit.c21
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 */
185static 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 */
241static 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 */
254static 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 */
171static 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
178void release_task(struct task_struct * p) 167void 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;
182repeat: 171repeat:
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);