aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamie Gritton <jamie@FreeBSD.org>2020-12-31 23:18:43 +0000
committerJamie Gritton <jamie@FreeBSD.org>2020-12-31 23:18:43 +0000
commitb4e87a632955a3a10ef6031c3d3e51c64e410749 (patch)
tree11f91d9127342104e42f2c998acf0bfe6b94a1c6
parent942951ba46ecd5ebab18de006a24dc52e2d3f745 (diff)
downloadsrc-b4e87a632955a3a10ef6031c3d3e51c64e410749.tar.gz
src-b4e87a632955a3a10ef6031c3d3e51c64e410749.zip
jail: Clean up allprison_lock handing in kern_jail_set
Keep explicit track of the allprison_lock state during the final part of kern_jail_set, instead of deducing it from the JAIL_ATTACH flag. Also properly clean up when the attachment fails, fixing a long- standing (though minor) memory leak.
-rw-r--r--sys/kern/kern_jail.c30
1 files changed, 18 insertions, 12 deletions
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index fb77cf87126d..1ecb023717bd 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -526,7 +526,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
#endif
unsigned long hid;
size_t namelen, onamelen, pnamelen;
- int born, created, cuflags, descend, enforce;
+ int born, created, cuflags, descend, enforce, slocked;
int error, errmsg_len, errmsg_pos;
int gotchildmax, gotenforce, gothid, gotrsnum, gotslevel;
int jid, jsys, len, level;
@@ -1828,24 +1828,32 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
}
/* Attach this process to the prison if requested. */
+ slocked = PD_LIST_SLOCKED;
if (flags & JAIL_ATTACH) {
mtx_lock(&pr->pr_mtx);
error = do_jail_attach(td, pr);
+ slocked = 0;
if (error) {
vfs_opterror(opts, "attach failed");
- if (!created)
- prison_deref(pr, PD_DEREF);
+ if (born) {
+ sx_slock(&allprison_lock);
+ slocked = PD_LIST_SLOCKED;
+ (void)osd_jail_call(pr, PR_METHOD_REMOVE, NULL);
+ }
+ prison_deref(pr, created
+ ? slocked
+ : PD_DEREF | slocked);
goto done_errmsg;
}
}
#ifdef RACCT
if (racct_enable && !created) {
- if (!(flags & JAIL_ATTACH))
+ if (slocked) {
sx_sunlock(&allprison_lock);
+ slocked = 0;
+ }
prison_racct_modify(pr);
- if (!(flags & JAIL_ATTACH))
- sx_slock(&allprison_lock);
}
#endif
@@ -1857,18 +1865,16 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
* (which was not done earlier so that the prison would not be publicly
* visible).
*/
- if (!created) {
- prison_deref(pr, (flags & JAIL_ATTACH)
- ? PD_DEREF
- : PD_DEREF | PD_LIST_SLOCKED);
- } else {
+ if (!created)
+ prison_deref(pr, PD_DEREF | slocked);
+ else {
if (pr_flags & PR_PERSIST) {
mtx_lock(&pr->pr_mtx);
pr->pr_ref++;
pr->pr_uref++;
mtx_unlock(&pr->pr_mtx);
}
- if (!(flags & JAIL_ATTACH))
+ if (slocked)
sx_sunlock(&allprison_lock);
}