Index: sys/kern/kern_exit.c =================================================================== --- sys/kern/kern_exit.c +++ sys/kern/kern_exit.c @@ -471,6 +471,7 @@ */ p->p_list.le_prev = NULL; #endif + prison_proc_unlink(p->p_ucred->cr_prison, p); sx_xunlock(&allproc_lock); sx_xlock(&proctree_lock); Index: sys/kern/kern_fork.c =================================================================== --- sys/kern/kern_fork.c +++ sys/kern/kern_fork.c @@ -397,6 +397,7 @@ sx_xlock(&allproc_lock); LIST_INSERT_HEAD(&allproc, p2, p_list); allproc_gen++; + prison_proc_link(p2->p_ucred->cr_prison, p2); sx_xunlock(&allproc_lock); sx_xlock(PIDHASHLOCK(p2->p_pid)); Index: sys/kern/kern_jail.c =================================================================== --- sys/kern/kern_jail.c +++ sys/kern/kern_jail.c @@ -145,6 +145,8 @@ static int prison_lock_xlock(struct prison *pr, int flags); static void prison_free_not_last(struct prison *pr); static void prison_proc_free_not_last(struct prison *pr); +static void prison_proc_relink(struct prison *opr, struct prison *npr, + struct proc *p); static void prison_set_allow_locked(struct prison *pr, unsigned flag, int enable); static char *prison_path(struct prison *pr1, struct prison *pr2); @@ -2646,6 +2648,7 @@ rctl_proc_ucred_changed(p, newcred); crfree(newcred); #endif + prison_proc_relink(oldcred->cr_prison, pr, p); prison_deref(oldcred->cr_prison, drflags); crfree(oldcred); @@ -2917,6 +2920,32 @@ #endif } +void +prison_proc_link(struct prison *pr, struct proc *p) +{ + + sx_assert(&allproc_lock, SA_XLOCKED); + LIST_INSERT_HEAD(&pr->pr_proclist, p, p_jaillist); +} + +void +prison_proc_unlink(struct prison *pr, struct proc *p) +{ + + sx_assert(&allproc_lock, SA_XLOCKED); + LIST_REMOVE(p, p_jaillist); +} + +static void +prison_proc_relink(struct prison *opr, struct prison *npr, struct proc *p) +{ + + sx_xlock(&allproc_lock); + prison_proc_unlink(opr, p); + prison_proc_link(npr, p); + sx_xunlock(&allproc_lock); +} + /* * Complete a call to either prison_free or prison_proc_free. */ @@ -2938,6 +2967,59 @@ prison_deref(pr, drflags); } +static void +prison_kill_processes_cb(struct proc *p, void *arg __unused) +{ + + kern_psignal(p, SIGKILL); +} + +void +prison_proc_iterate(struct prison *pr, void (*cb)(struct proc *, void *), + void *cbarg) +{ + struct prison *ppr; + struct proc *p; + + MPASS(pr != NULL); + + if (LIST_EMPTY(&pr->pr_proclist)) { + return; + } + + if (pr->pr_childcount == 0) { + sx_slock(&allproc_lock); + FOREACH_PROC_IN_PRISON(p, pr) { + if (p->p_state == PRS_NEW) + continue; + PROC_LOCK(p); + cb(p, cbarg); + PROC_UNLOCK(p); + } + sx_sunlock(&allproc_lock); + return; + } + + sx_slock(&allproc_lock); + FOREACH_PROC_IN_SYSTEM(p) { + if (p->p_state == PRS_NEW) + continue; + PROC_LOCK(p); + if (p->p_ucred != NULL) { + for (ppr = p->p_ucred->cr_prison; + ppr != &prison0; + ppr = ppr->pr_parent) { + if (ppr == pr) { + cb(p, cbarg); + break; + } + } + } + PROC_UNLOCK(p); + } + sx_sunlock(&allproc_lock); +} + /* * Remove a prison reference and/or user reference (usually). * This assumes context that allows sleeping (for allprison_lock), @@ -2951,7 +3033,6 @@ { struct prisonlist freeprison; struct prison *killpr, *rpr, *ppr, *tpr; - struct proc *p; killpr = NULL; TAILQ_INIT(&freeprison); @@ -3063,23 +3144,8 @@ sx_xunlock(&allprison_lock); /* Kill any processes attached to a killed prison. */ - if (killpr != NULL) { - sx_slock(&allproc_lock); - FOREACH_PROC_IN_SYSTEM(p) { - PROC_LOCK(p); - if (p->p_state != PRS_NEW && p->p_ucred != NULL) { - for (ppr = p->p_ucred->cr_prison; - ppr != &prison0; - ppr = ppr->pr_parent) - if (ppr == killpr) { - kern_psignal(p, SIGKILL); - break; - } - } - PROC_UNLOCK(p); - } - sx_sunlock(&allproc_lock); - } + if (killpr != NULL) + prison_proc_iterate(killpr, prison_kill_processes_cb, NULL); /* * Finish removing any unreferenced prisons, which couldn't happen Index: sys/kern/kern_sig.c =================================================================== --- sys/kern/kern_sig.c +++ sys/kern/kern_sig.c @@ -1713,18 +1713,13 @@ }; static void -killpg1_sendsig(struct proc *p, bool notself, struct killpg1_ctx *arg) +killpg1_sendsig_locked(struct proc *p, struct killpg1_ctx *arg) { int err; - if (p->p_pid <= 1 || (p->p_flag & P_SYSTEM) != 0 || - (notself && p == arg->td->td_proc) || p->p_state == PRS_NEW) - return; - PROC_LOCK(p); err = p_cansignal(arg->td, p, arg->sig); if (err == 0 && arg->sig != 0) pksignal(p, arg->sig, arg->ksi); - PROC_UNLOCK(p); if (err != ESRCH) arg->found = true; if (err == 0) @@ -1733,6 +1728,31 @@ arg->ret = err; } +static void +killpg1_sendsig(struct proc *p, bool notself, struct killpg1_ctx *arg) +{ + + if (p->p_pid <= 1 || (p->p_flag & P_SYSTEM) != 0 || + (notself && p == arg->td->td_proc) || p->p_state == PRS_NEW) + return; + + PROC_LOCK(p); + killpg1_sendsig_locked(p, arg); + PROC_UNLOCK(p); +} + +static void +kill_processes_prison_cb(struct proc *p, void *arg) +{ + struct killpg1_ctx *ctx = arg; + + if (p->p_pid <= 1 || (p->p_flag & P_SYSTEM) != 0 || + (p == ctx->td->td_proc) || p->p_state == PRS_NEW) + return; + + killpg1_sendsig_locked(p, ctx); +} + /* * Common code for kill process group/broadcast kill. * cp is calling process. @@ -1754,11 +1774,8 @@ /* * broadcast */ - sx_slock(&allproc_lock); - FOREACH_PROC_IN_SYSTEM(p) { - killpg1_sendsig(p, true, &arg); - } - sx_sunlock(&allproc_lock); + prison_proc_iterate(td->td_ucred->cr_prison, + kill_processes_prison_cb, &arg); } else { sx_slock(&proctree_lock); if (pgid == 0) { Index: sys/sys/jail.h =================================================================== --- sys/sys/jail.h +++ sys/sys/jail.h @@ -176,6 +176,7 @@ volatile u_int pr_uref; /* (r) user (alive) refcount */ unsigned pr_flags; /* (p) PR_* flags */ LIST_HEAD(, prison) pr_children; /* (a) list of child jails */ + LIST_HEAD(, proc) pr_proclist; /* (a) list of jailed processes */ LIST_ENTRY(prison) pr_sibling; /* (a) next in parent's list */ struct prison *pr_parent; /* (c) containing jail */ struct mtx pr_mtx; @@ -359,6 +360,9 @@ ? LIST_NEXT(cpr, pr_sibling) \ : cpr->pr_parent) != (ppr);) +#define FOREACH_PROC_IN_PRISON(p, pr) \ + LIST_FOREACH((p), &pr->pr_proclist, p_jaillist) + /* * Attributes of the physical system, and the root of the jail tree. */ @@ -432,6 +436,9 @@ void prison_hold_locked(struct prison *pr); void prison_proc_hold(struct prison *); void prison_proc_free(struct prison *); +void prison_proc_link(struct prison *, struct proc *); +void prison_proc_unlink(struct prison *, struct proc *); +void prison_proc_iterate(struct prison *, void (*)(struct proc *, void *), void *); void prison_set_allow(struct ucred *cred, unsigned flag, int enable); int prison_ischild(struct prison *, struct prison *); bool prison_isalive(const struct prison *); Index: sys/sys/proc.h =================================================================== --- sys/sys/proc.h +++ sys/sys/proc.h @@ -744,6 +744,7 @@ LIST_HEAD(, proc) p_orphans; /* (e) Pointer to list of orphans. */ TAILQ_HEAD(, kq_timer_cb_data) p_kqtim_stop; /* (c) */ + LIST_ENTRY(proc) p_jaillist; /* (d) Jail process linkage. */ }; #define p_session p_pgrp->pg_session