summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_jail.c
diff options
context:
space:
mode:
authorjamie <jamie@FreeBSD.org>2016-06-15 01:56:20 +0000
committerjamie <jamie@FreeBSD.org>2016-06-15 01:56:20 +0000
commitcbbf6bc8819be31168b6d7024888140a1caa07ae (patch)
tree40f334f33e062e615b5d1da34d78ea057091b1c4 /sys/kern/kern_jail.c
parentd7aadcbe8c8711fd02ae2ce7da26b1ed7efc2ea7 (diff)
downloadFreeBSD-src-cbbf6bc8819be31168b6d7024888140a1caa07ae.zip
FreeBSD-src-cbbf6bc8819be31168b6d7024888140a1caa07ae.tar.gz
MFC r301745:
Make sure the OSD methods for jail set and remove can't run concurrently, by holding allprison_lock exclusively (even if only for a moment before downgrading) on all paths that call PR_METHOD_REMOVE. Since they may run on a downgraded lock, it's still possible for them to run concurrently with PR_METHOD_GET, which will need to use the prison lock.
Diffstat (limited to 'sys/kern/kern_jail.c')
-rw-r--r--sys/kern/kern_jail.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index 770419b..ed2565a 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -2400,7 +2400,14 @@ sys_jail_attach(struct thread *td, struct jail_attach_args *uap)
if (error)
return (error);
- sx_slock(&allprison_lock);
+ /*
+ * Start with exclusive hold on allprison_lock to ensure that a possible
+ * PR_METHOD_REMOVE call isn't concurrent with jail_set or jail_remove.
+ * But then immediately downgrade it since we don't need to stop
+ * readers.
+ */
+ sx_xlock(&allprison_lock);
+ sx_downgrade(&allprison_lock);
pr = prison_find_child(td->td_ucred->cr_prison, uap->jid);
if (pr == NULL) {
sx_sunlock(&allprison_lock);
@@ -2618,9 +2625,11 @@ prison_complete(void *context, int pending)
{
struct prison *pr = context;
+ sx_xlock(&allprison_lock);
mtx_lock(&pr->pr_mtx);
prison_deref(pr, pr->pr_uref
- ? PD_DEREF | PD_DEUREF | PD_LOCKED : PD_LOCKED);
+ ? PD_DEREF | PD_DEUREF | PD_LOCKED | PD_LIST_XLOCKED
+ : PD_LOCKED | PD_LIST_XLOCKED);
}
/*
@@ -2664,13 +2673,8 @@ prison_deref(struct prison *pr, int flags)
*/
if (lasturef) {
if (!(flags & (PD_LIST_SLOCKED | PD_LIST_XLOCKED))) {
- if (ref > 1) {
- sx_slock(&allprison_lock);
- flags |= PD_LIST_SLOCKED;
- } else {
- sx_xlock(&allprison_lock);
- flags |= PD_LIST_XLOCKED;
- }
+ sx_xlock(&allprison_lock);
+ flags |= PD_LIST_XLOCKED;
}
(void)osd_jail_call(pr, PR_METHOD_REMOVE, NULL);
mtx_lock(&pr->pr_mtx);
OpenPOWER on IntegriCloud