Subject: [PATCH] Cause the termination of the pspace leader to terminate all of it's children From: Eric W. Biederman Date: 1129919881 -0600 --- include/linux/pspace.h | 9 +++++++++ include/linux/sched.h | 2 ++ kernel/exit.c | 33 ++++++++++++++++++++++++++++----- kernel/signal.c | 5 ++--- 4 files changed, 41 insertions(+), 8 deletions(-) f694494c1f4983b64ea82c5b2b9139e93ec3e994 diff --git a/include/linux/pspace.h b/include/linux/pspace.h index 770fdf3..6a05210 100644 --- a/include/linux/pspace.h +++ b/include/linux/pspace.h @@ -75,5 +75,14 @@ static inline void exit_pspace(struct ta tsk->pspace = NULL; } +static inline int pspace_leader(struct task_struct *tsk) +{ + return tsk == tsk->pspace->child_reaper; +} + +static inline int delay_pspace_leader(struct task_struct *tsk) +{ + return pspace_leader(tsk) && (tsk->pspace->nr_processes > 1); +} #endif /* _LINUX_PSPACE_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 43f5afd..0b01c97 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1016,6 +1016,8 @@ extern int send_sig_info(int, struct sig extern int send_group_sig_info(int, struct siginfo *, struct task_struct *); extern int force_sigsegv(int, struct task_struct *); extern int force_sig_info(int, struct siginfo *, struct task_struct *); +extern int __kill_pspace_info(int sig, struct siginfo *info, pid_t pspaceid); +extern int kill_pspace_info(int sig, struct siginfo *info, pid_t pspaceid); extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp); extern int kill_pg_info(int, struct siginfo *, pid_t); extern int kill_proc_info(int, struct siginfo *, pid_t); diff --git a/kernel/exit.c b/kernel/exit.c index 82b39c0..aa349bf 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -562,9 +562,11 @@ static inline void reparent_thread(task_ * anyway, so let go of it. */ p->ptrace = 0; - list_del_init(&p->sibling); - p->parent = p->real_parent; - list_add_tail(&p->sibling, &p->parent->children); + if (p->parent != p->real_parent) { + list_del_init(&p->sibling); + p->parent = p->real_parent; + list_add_tail(&p->sibling, &p->parent->children); + } /* If we'd notified the old parent about this child's death, * also notify the new parent. @@ -619,6 +621,7 @@ static inline void forget_original_paren } } while (reaper->exit_state); + /* * There are only two places where our children can be: * @@ -710,7 +713,7 @@ static void exit_notify(struct task_stru INIT_LIST_HEAD(&ptrace_dead); forget_original_parent(tsk, &ptrace_dead); - BUG_ON(!list_empty(&tsk->children)); + BUG_ON(!pspace_leader(tsk) && !list_empty(&tsk->children)); BUG_ON(!list_empty(&tsk->ptrace_children)); /* @@ -733,6 +736,18 @@ static void exit_notify(struct task_stru __kill_pg_info(SIGCONT, (void *)1, process_group(tsk)); } + + /* + * Check to see if we are the pspace leader. + * If so it is nonsense for the pspace to continue so set + * the SIGCHLD handler to SIG_IGN and kill everyone + * else in the pspace. + */ + if (pspace_leader(tsk)) { + tsk->sighand->action[SIGCHLD-1].sa.sa_handler = SIG_IGN; + __kill_pspace_info(SIGKILL, (void *)1, tsk->tgid); + } + /* Let father know we died * * Thread signals are configurable, but you aren't going to use @@ -804,7 +819,7 @@ fastcall NORET_TYPE void do_exit(long co panic("Aiee, killing interrupt handler!"); if (unlikely(!tsk->pid)) panic("Attempted to kill the idle task!"); - if (unlikely(tsk->pid == 1)) + if (unlikely((tsk->pid == 1) && (tsk->pspace == &init_pspace))) panic("Attempted to kill init!"); if (tsk->io_context) exit_io_context(); @@ -979,6 +994,14 @@ static int eligible_child(pid_t pid, int if (current->tgid != p->tgid && delay_group_leader(p)) return 2; + + /* + * Do not consider pspace leaders that are in + * a non-empty pspace. + */ + if (delay_pspace_leader(p)) + return 2; + if (security_task_wait(p)) return 0; diff --git a/kernel/signal.c b/kernel/signal.c index 6378175..6349ab5 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1165,7 +1165,7 @@ int __kill_pspace_info(int sig, struct s max = pspace->offset + pspace->max; for_each_process(p) { - if ((p->pid != current->pspace->offset + 1) && (p->tgid != current->tgid) && + if ((p != current->pspace->child_reaper) && (p->tgid != current->tgid) && (p->pid > min) && (p->pid < max)) { int err = group_send_sig_info(sig, info, p); @@ -1177,8 +1177,7 @@ int __kill_pspace_info(int sig, struct s return count ? retval : -ESRCH; } -int -kill_pspace_info(int sig, struct siginfo *info, pid_t pspaceid) +int kill_pspace_info(int sig, struct siginfo *info, pid_t pspaceid) { int retval; -- 1.0.GIT