Page MenuHomeFreeBSD

D28515.id83519.diff
No OneTemporary

D28515.id83519.diff

diff --git a/kern/kern_fork.c b/kern/kern_fork_28515.c
--- a/kern/kern_fork.c
+++ b/kern/kern_fork_28515.c
@@ -688,6 +688,13 @@
p2->p_state = PRS_NORMAL;
PROC_SUNLOCK(p2);
+ /*
+ * If the prison was killed while the process was new, die along
+ * with it.
+ */
+ if (!prison_isalive(p2->p_ucred->cr_prison))
+ kern_psignal(p2, SIGKILL);
+
#ifdef KDTRACE_HOOKS
/*
* Tell the DTrace fasttrap provider about the new process so that any
diff --git a/kern/kern_jail_28473.c b/kern/kern_jail_28515.c
--- a/kern/kern_jail_28473.c
+++ b/kern/kern_jail_28515.c
@@ -144,7 +144,6 @@
static void prison_deref_kill(struct prison *pr, struct prisonlist *freeprison);
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_set_allow_locked(struct prison *pr, unsigned flag,
int enable);
static char *prison_path(struct prison *pr1, struct prison *pr2);
@@ -1000,6 +999,11 @@
}
sx_xlock(&allprison_lock);
drflags = PD_LIST_XLOCKED;
+ if (!prison_isalive(mypr)) {
+ /* This jail is dying. This process will surely follow. */
+ error = EAGAIN;
+ goto done_deref;
+ }
if (jid != 0) {
if (jid < 0) {
error = EINVAL;
@@ -1111,8 +1115,7 @@
"jail \"%s\" not found", name);
goto done_deref;
}
- if (!(flags & JAIL_DYING) &&
- !prison_isalive(ppr)) {
+ if (!prison_isalive(ppr)) {
mtx_unlock(&ppr->pr_mtx);
error = ENOENT;
vfs_opterror(opts,
@@ -1202,19 +1205,7 @@
goto done_deref;
}
prison_hold(ppr);
- if (!refcount_acquire_if_not_zero(&ppr->pr_uref)) {
- /* This brings the parent back to life. */
- mtx_lock(&ppr->pr_mtx);
- refcount_acquire(&ppr->pr_uref);
- ppr->pr_state = PRISON_STATE_ALIVE;
- mtx_unlock(&ppr->pr_mtx);
- error = osd_jail_call(ppr, PR_METHOD_CREATE, opts);
- if (error) {
- pr = ppr;
- drflags |= PD_DEREF | PD_DEUREF;
- goto done_deref;
- }
- }
+ prison_proc_hold(ppr);
if (jid == 0 && (jid = get_next_prid(&inspr)) == 0) {
error = EAGAIN;
@@ -2416,6 +2407,18 @@
#endif
prison_deref(oldcred->cr_prison, drflags);
crfree(oldcred);
+
+ /*
+ * If the prison was killed while changing credentials, die along
+ * with it.
+ */
+ if (!prison_isalive(pr)) {
+ /* Follow the prison into death. */
+ PROC_LOCK(p);
+ kern_psignal(p, SIGKILL);
+ PROC_UNLOCK(p);
+ }
+
return (0);
e_unlock:
@@ -2606,7 +2609,8 @@
* user-visible, except through the the jail system calls. It is also
* an error to hold an invalid prison. A prison record will remain
* alive as long as it has at least one user reference, and will not
- * be set to the dying state was long as the prison mutex is held.
+ * be set to the dying state was long as either the prison mutex or
+ * the allprison lock is held (allprison_lock may be shared).
*/
void
prison_proc_hold(struct prison *pr)
@@ -2655,24 +2659,6 @@
}
}
-static void
-prison_proc_free_not_last(struct prison *pr)
-{
-#ifdef INVARIANTS
- int lastref;
-
- KASSERT(refcount_load(&pr->pr_uref) > 0,
- ("Trying to free dead prison %p (jid=%d).",
- pr, pr->pr_id));
- lastref = refcount_release(&pr->pr_uref);
- KASSERT(!lastref,
- ("prison_free_not_last freed last ref on prison %p (jid=%d).",
- pr, pr->pr_id));
-#else
- refcount_release(&pr>pr_uref);
-#endif
-}
-
/*
* Complete a call to either prison_free or prison_proc_free.
*/
@@ -2720,25 +2706,13 @@
for (;;) {
if (flags & PD_KILL) {
/* Kill the prison and its descendents. */
- flags &= ~PD_KILL;
if (!(flags & PD_DEREF)) {
prison_hold(pr);
flags |= PD_DEREF;
}
flags = prison_lock_xlock(pr, flags);
- if (pr->pr_state != PRISON_STATE_DYING) {
- /*
- * The prison might currently be invalid,
- * but call it alive now so PD_DEUREF will
- * notice it later.
- */
- pr->pr_state = PRISON_STATE_ALIVE;
- if (!(flags & PD_DEUREF)) {
- refcount_acquire(&pr->pr_uref);
- flags |= PD_DEUREF;
- }
+ if (pr->pr_state != PRISON_STATE_DYING)
prison_deref_kill(pr, &freeprison);
- }
}
if (flags & PD_DEUREF) {
/* Drop a user reference. */
@@ -2890,41 +2864,56 @@
static void
prison_deref_kill(struct prison *pr, struct prisonlist *freeprison)
{
- struct prison *cpr, *ppr;
+ struct prison *cpr, *ppr, *rpr;
bool descend;
/*
- * The operation each descendant is similar to what prison_deref()
- * does when losing the last references, plus clearing PR_PERSIST.
+ * The operation for the prison and each descendant is similar to
+ * what prison_deref() does when losing the last references, plus
+ * clearing PR_PERSIST.
*/
+ pr->pr_state = PRISON_STATE_DYING;
mtx_unlock(&pr->pr_mtx);
+ rpr = NULL;
FOREACH_PRISON_DESCENDANT_PRE_POST(pr, cpr, descend) {
- if (!prison_isalive(cpr))
- continue;
if (descend) {
+ if (!prison_isalive(cpr)) {
+ descend = false;
+ continue;
+ }
prison_hold(cpr);
- prison_proc_hold(cpr);
+ mtx_lock(&cpr->pr_mtx);
+ cpr->pr_state = PRISON_STATE_DYING;
+ cpr->pr_flags |= PR_REMOVE;
+ mtx_unlock(&cpr->pr_mtx);
continue;
}
+ if (!(cpr->pr_flags & PR_REMOVE))
+ continue;
+ if (rpr != NULL) {
+ LIST_REMOVE(rpr, pr_sibling);
+ rpr = NULL;
+ }
+ (void)osd_jail_call(cpr, PR_METHOD_REMOVE, NULL);
mtx_lock(&cpr->pr_mtx);
+ cpr->pr_flags &= ~PR_REMOVE;
if (cpr->pr_flags & PR_PERSIST) {
cpr->pr_flags &= ~PR_PERSIST;
- prison_proc_free_not_last(cpr);
+ (void)refcount_release(&cpr->pr_uref);
prison_free_not_last(cpr);
}
- if (refcount_release(&cpr->pr_uref)) {
- cpr->pr_state = PRISON_STATE_DYING;
- mtx_unlock(&cpr->pr_mtx);
- (void)osd_jail_call(cpr, PR_METHOD_REMOVE, NULL);
- mtx_lock(&cpr->pr_mtx);
- }
if (refcount_release(&cpr->pr_ref)) {
- cpr->pr_state = PRISON_STATE_INVALID;
- TAILQ_REMOVE(&allprison, cpr, pr_list);
- TAILQ_INSERT_TAIL(freeprison, cpr, pr_list);
- mtx_unlock(&cpr->pr_mtx);
- ppr = cpr->pr_parent;
- prison_proc_free_not_last(ppr);
+ rpr = cpr;
+ rpr->pr_state = PRISON_STATE_INVALID;
+ mtx_unlock(&rpr->pr_mtx);
+ TAILQ_REMOVE(&allprison, rpr, pr_list);
+ TAILQ_INSERT_TAIL(freeprison, rpr, pr_list);
+ ppr = rpr->pr_parent;
+ if (!refcount_release_if_not_last(&ppr->pr_uref)) {
+ mtx_lock(&ppr->pr_mtx);
+ (void)refcount_release(&ppr->pr_uref);
+ mtx_unlock(&ppr->pr_mtx);
+ }
prison_free_not_last(ppr);
for (; ppr != NULL; ppr = ppr->pr_parent)
ppr->pr_childcount--;
@@ -2932,20 +2921,16 @@
else
mtx_unlock(&cpr->pr_mtx);
}
+ if (rpr != NULL)
+ LIST_REMOVE(rpr, pr_sibling);
+ (void)osd_jail_call(pr, PR_METHOD_REMOVE, NULL);
mtx_lock(&pr->pr_mtx);
if (pr->pr_flags & PR_PERSIST) {
pr->pr_flags &= ~PR_PERSIST;
- prison_proc_free_not_last(pr);
+ (void)refcount_release(&pr->pr_uref);
prison_free_not_last(pr);
}
-
- /*
- * Disconnect unreferenced descendants from their parents,
- * which couldn't easily be done mid-loop.
- */
- TAILQ_FOREACH(cpr, freeprison, pr_list)
- LIST_REMOVE(cpr, pr_sibling);
}
/*
@@ -3146,8 +3131,7 @@
}
/*
- * Return true if the prison is currently alive. A prison is alive if it
- * holds user references.
+ * Return true if the prison is currently alive.
*/
bool
prison_isalive(struct prison *pr)
diff --git a/sys/jail_28473.h b/sys/jail_28515.h
--- a/sys/jail_28473.h
+++ b/sys/jail_28515.h
@@ -221,6 +221,7 @@
/* primary jail address. */
/* Internal flag bits */
+#define PR_REMOVE 0x01000000 /* In process of being removed */
#define PR_IP4 0x02000000 /* IPv4 restricted or disabled */
/* by this jail or an ancestor */
#define PR_IP6 0x04000000 /* IPv6 restricted or disabled */

File Metadata

Mime Type
text/plain
Expires
Mon, May 25, 11:15 PM (17 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33518666
Default Alt Text
D28515.id83519.diff (7 KB)

Event Timeline