Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F159545122
D28515.id84344.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D28515.id84344.diff
View Options
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.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;
@@ -1758,7 +1749,6 @@
}
}
pr->pr_flags = (pr->pr_flags & ~ch_flags) | pr_flags;
- pr->pr_flags &= ~PR_REMOVE;
mtx_unlock(&pr->pr_mtx);
drflags &= ~PD_LOCKED;
/*
@@ -2423,6 +2413,7 @@
* with it.
*/
if (!prison_isalive(pr)) {
+ /* Follow the prison into death. */
PROC_LOCK(p);
kern_psignal(p, SIGKILL);
PROC_UNLOCK(p);
@@ -2618,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)
@@ -2667,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.
*/
@@ -2732,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. */
@@ -2902,48 +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) {
- /*
- * Mark the prison as doomed, so it doesn't accidentally
- * come back to life. It may still be explicitly brought
- * back by jail_set(2).
- */
- pr->pr_flags |= PR_REMOVE;
-
- 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--;
@@ -2951,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);
}
/*
@@ -3173,8 +3139,6 @@
{
if (__predict_false(pr->pr_state != PRISON_STATE_ALIVE))
- return (false);
- if (__predict_false(pr->pr_flags & PR_REMOVE))
return (false);
return (true);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Jun 16, 2:13 PM (12 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33989317
Default Alt Text
D28515.id84344.diff (6 KB)
Attached To
Mode
D28515: Don't allow jail "accidental" resurrection of dead jails.
Attached
Detach File
Event Timeline
Log In to Comment