mirror of
https://github.com/opnsense/src.git
synced 2026-04-21 22:27:47 -04:00
Fix ktrace enablement/disablement races that can result in a vnode
ref count panic. Bug noticed by: ps Reviewed by: ps MFC after: 1 day
This commit is contained in:
parent
3f498bf72b
commit
79deba82cd
4 changed files with 66 additions and 17 deletions
|
|
@ -335,9 +335,13 @@ interpret:
|
|||
*/
|
||||
setsugid(p);
|
||||
if (p->p_tracep && suser_xxx(oldcred, NULL, PRISON_ROOT)) {
|
||||
p->p_traceflag = 0;
|
||||
vrele(p->p_tracep);
|
||||
p->p_tracep = NULL;
|
||||
struct vnode *vtmp;
|
||||
|
||||
if ((vtmp = p->p_tracep) != NULL) {
|
||||
p->p_tracep = NULL;
|
||||
p->p_traceflag = 0;
|
||||
vrele(vtmp);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Set the new credentials.
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ exit1(td, rv)
|
|||
struct proc *p = td->td_proc;
|
||||
register struct proc *q, *nq;
|
||||
register struct vmspace *vm;
|
||||
struct vnode *vtmp;
|
||||
struct exitlist *ep;
|
||||
|
||||
GIANT_REQUIRED;
|
||||
|
|
@ -275,8 +276,10 @@ exit1(td, rv)
|
|||
* release trace file
|
||||
*/
|
||||
p->p_traceflag = 0; /* don't trace the vrele() */
|
||||
if (p->p_tracep)
|
||||
vrele(p->p_tracep);
|
||||
if ((vtmp = p->p_tracep) != NULL) {
|
||||
p->p_tracep = NULL;
|
||||
vrele(vtmp);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Remove proc from allproc queue and pidhash chain.
|
||||
|
|
|
|||
|
|
@ -585,10 +585,11 @@ again:
|
|||
PROC_LOCK(p1);
|
||||
#ifdef KTRACE
|
||||
/*
|
||||
* Copy traceflag and tracefile if enabled.
|
||||
* If not inherited, these were zeroed above.
|
||||
* Copy traceflag and tracefile if enabled. If not inherited,
|
||||
* these were zeroed above but we still could have a trace race
|
||||
* so make sure p2's p_tracep is NULL.
|
||||
*/
|
||||
if (p1->p_traceflag & KTRFAC_INHERIT) {
|
||||
if ((p1->p_traceflag & KTRFAC_INHERIT) && p2->p_tracep == NULL) {
|
||||
p2->p_traceflag = p1->p_traceflag;
|
||||
if ((p2->p_tracep = p1->p_tracep) != NULL) {
|
||||
PROC_UNLOCK(p1);
|
||||
|
|
|
|||
|
|
@ -150,12 +150,19 @@ ktrnamei(vp, path)
|
|||
struct ktr_header *kth;
|
||||
struct proc *p = curproc; /* XXX */
|
||||
|
||||
/*
|
||||
* don't let p_tracep get ripped out from under us
|
||||
*/
|
||||
if (vp)
|
||||
VREF(vp);
|
||||
p->p_traceflag |= KTRFAC_ACTIVE;
|
||||
kth = ktrgetheader(KTR_NAMEI);
|
||||
kth->ktr_len = strlen(path);
|
||||
kth->ktr_buffer = path;
|
||||
|
||||
ktrwrite(vp, kth, NULL);
|
||||
if (vp)
|
||||
vrele(vp);
|
||||
FREE(kth, M_KTRACE);
|
||||
p->p_traceflag &= ~KTRFAC_ACTIVE;
|
||||
}
|
||||
|
|
@ -174,6 +181,11 @@ ktrgenio(vp, fd, rw, uio, error)
|
|||
|
||||
if (error)
|
||||
return;
|
||||
/*
|
||||
* don't let p_tracep get ripped out from under us
|
||||
*/
|
||||
if (vp)
|
||||
VREF(vp);
|
||||
p->p_traceflag |= KTRFAC_ACTIVE;
|
||||
kth = ktrgetheader(KTR_GENIO);
|
||||
ktg.ktr_fd = fd;
|
||||
|
|
@ -184,6 +196,8 @@ ktrgenio(vp, fd, rw, uio, error)
|
|||
uio->uio_rw = UIO_WRITE;
|
||||
|
||||
ktrwrite(vp, kth, uio);
|
||||
if (vp)
|
||||
vrele(vp);
|
||||
FREE(kth, M_KTRACE);
|
||||
p->p_traceflag &= ~KTRFAC_ACTIVE;
|
||||
}
|
||||
|
|
@ -200,6 +214,11 @@ ktrpsig(vp, sig, action, mask, code)
|
|||
struct ktr_psig kp;
|
||||
struct proc *p = curproc; /* XXX */
|
||||
|
||||
/*
|
||||
* don't let vp get ripped out from under us
|
||||
*/
|
||||
if (vp)
|
||||
VREF(vp);
|
||||
p->p_traceflag |= KTRFAC_ACTIVE;
|
||||
kth = ktrgetheader(KTR_PSIG);
|
||||
kp.signo = (char)sig;
|
||||
|
|
@ -210,6 +229,8 @@ ktrpsig(vp, sig, action, mask, code)
|
|||
kth->ktr_len = sizeof (struct ktr_psig);
|
||||
|
||||
ktrwrite(vp, kth, NULL);
|
||||
if (vp)
|
||||
vrele(vp);
|
||||
FREE(kth, M_KTRACE);
|
||||
p->p_traceflag &= ~KTRFAC_ACTIVE;
|
||||
}
|
||||
|
|
@ -223,6 +244,11 @@ ktrcsw(vp, out, user)
|
|||
struct ktr_csw kc;
|
||||
struct proc *p = curproc; /* XXX */
|
||||
|
||||
/*
|
||||
* don't let vp get ripped out from under us
|
||||
*/
|
||||
if (vp)
|
||||
VREF(vp);
|
||||
p->p_traceflag |= KTRFAC_ACTIVE;
|
||||
kth = ktrgetheader(KTR_CSW);
|
||||
kc.out = out;
|
||||
|
|
@ -231,6 +257,8 @@ ktrcsw(vp, out, user)
|
|||
kth->ktr_len = sizeof (struct ktr_csw);
|
||||
|
||||
ktrwrite(vp, kth, NULL);
|
||||
if (vp)
|
||||
vrele(vp);
|
||||
FREE(kth, M_KTRACE);
|
||||
p->p_traceflag &= ~KTRFAC_ACTIVE;
|
||||
}
|
||||
|
|
@ -289,19 +317,20 @@ ktrace(td, uap)
|
|||
}
|
||||
}
|
||||
/*
|
||||
* Clear all uses of the tracefile
|
||||
* Clear all uses of the tracefile.
|
||||
*/
|
||||
if (ops == KTROP_CLEARFILE) {
|
||||
sx_slock(&allproc_lock);
|
||||
LIST_FOREACH(p, &allproc, p_list) {
|
||||
if (p->p_tracep == vp) {
|
||||
if (ktrcanset(curp, p)) {
|
||||
if (ktrcanset(curp, p) && p->p_tracep == vp) {
|
||||
p->p_tracep = NULL;
|
||||
p->p_traceflag = 0;
|
||||
(void) vn_close(vp, FREAD|FWRITE,
|
||||
p->p_ucred, td);
|
||||
} else
|
||||
} else {
|
||||
error = EPERM;
|
||||
}
|
||||
}
|
||||
}
|
||||
sx_sunlock(&allproc_lock);
|
||||
|
|
@ -371,6 +400,7 @@ utrace(td, uap)
|
|||
#ifdef KTRACE
|
||||
struct ktr_header *kth;
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct vnode *vp;
|
||||
register caddr_t cp;
|
||||
|
||||
if (!KTRPOINT(p, KTR_USER))
|
||||
|
|
@ -378,13 +408,17 @@ utrace(td, uap)
|
|||
if (uap->len > KTR_USER_MAXLEN)
|
||||
return (EINVAL);
|
||||
p->p_traceflag |= KTRFAC_ACTIVE;
|
||||
if ((vp = p->p_tracep) != NULL)
|
||||
VREF(vp);
|
||||
kth = ktrgetheader(KTR_USER);
|
||||
MALLOC(cp, caddr_t, uap->len, M_KTRACE, M_WAITOK);
|
||||
if (!copyin(uap->addr, cp, uap->len)) {
|
||||
kth->ktr_buffer = cp;
|
||||
kth->ktr_len = uap->len;
|
||||
ktrwrite(p->p_tracep, kth, NULL);
|
||||
ktrwrite(vp, kth, NULL);
|
||||
}
|
||||
if (vp)
|
||||
vrele(vp);
|
||||
FREE(kth, M_KTRACE);
|
||||
FREE(cp, M_KTRACE);
|
||||
p->p_traceflag &= ~KTRFAC_ACTIVE;
|
||||
|
|
@ -407,12 +441,16 @@ ktrops(curp, p, ops, facs, vp)
|
|||
return (0);
|
||||
if (ops == KTROP_SET) {
|
||||
if (p->p_tracep != vp) {
|
||||
struct vnode *vtmp;
|
||||
|
||||
/*
|
||||
* if trace file already in use, relinquish
|
||||
*/
|
||||
if (p->p_tracep != NULL)
|
||||
vrele(p->p_tracep);
|
||||
VREF(vp);
|
||||
while ((vtmp = p->p_tracep) != NULL) {
|
||||
p->p_tracep = NULL;
|
||||
vrele(vtmp);
|
||||
}
|
||||
p->p_tracep = vp;
|
||||
}
|
||||
p->p_traceflag |= facs;
|
||||
|
|
@ -421,11 +459,13 @@ ktrops(curp, p, ops, facs, vp)
|
|||
} else {
|
||||
/* KTROP_CLEAR */
|
||||
if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
|
||||
struct vnode *vtmp;
|
||||
|
||||
/* no more tracing */
|
||||
p->p_traceflag = 0;
|
||||
if (p->p_tracep != NULL) {
|
||||
vrele(p->p_tracep);
|
||||
if ((vtmp = p->p_tracep) != NULL) {
|
||||
p->p_tracep = NULL;
|
||||
vrele(vtmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -513,7 +553,8 @@ ktrwrite(vp, kth, uio)
|
|||
if (!error)
|
||||
return;
|
||||
/*
|
||||
* If error encountered, give up tracing on this vnode.
|
||||
* If error encountered, give up tracing on this vnode. XXX what
|
||||
* happens to the loop if vrele() blocks?
|
||||
*/
|
||||
log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
|
||||
error);
|
||||
|
|
|
|||
Loading…
Reference in a new issue