Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157765430
D28515.id83519.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D28515.id83519.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D28515: Don't allow jail "accidental" resurrection of dead jails.
Attached
Detach File
Event Timeline
Log In to Comment