Fix a credential reference leak. [1]
Close subtle but relatively unlikely race conditions when propagating the vnode write error to other active sessions tracing to the same vnode, without holding a reference on the vnode anymore. [2] PR: kern/126368 [1] Submitted by: rwatson [2] Reviewed by: kib, rwatson MFC after: 4 weeks
This commit is contained in:
parent
a10c6ee6bd
commit
118258f5c2
@ -907,12 +907,7 @@ ktr_writerequest(struct thread *td, struct ktr_request *req)
|
|||||||
*/
|
*/
|
||||||
mtx_lock(&ktrace_mtx);
|
mtx_lock(&ktrace_mtx);
|
||||||
vp = td->td_proc->p_tracevp;
|
vp = td->td_proc->p_tracevp;
|
||||||
if (vp != NULL)
|
|
||||||
VREF(vp);
|
|
||||||
cred = td->td_proc->p_tracecred;
|
cred = td->td_proc->p_tracecred;
|
||||||
if (cred != NULL)
|
|
||||||
crhold(cred);
|
|
||||||
mtx_unlock(&ktrace_mtx);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If vp is NULL, the vp has been cleared out from under this
|
* If vp is NULL, the vp has been cleared out from under this
|
||||||
@ -921,9 +916,13 @@ ktr_writerequest(struct thread *td, struct ktr_request *req)
|
|||||||
*/
|
*/
|
||||||
if (vp == NULL) {
|
if (vp == NULL) {
|
||||||
KASSERT(cred == NULL, ("ktr_writerequest: cred != NULL"));
|
KASSERT(cred == NULL, ("ktr_writerequest: cred != NULL"));
|
||||||
|
mtx_unlock(&ktrace_mtx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
VREF(vp);
|
||||||
KASSERT(cred != NULL, ("ktr_writerequest: cred == NULL"));
|
KASSERT(cred != NULL, ("ktr_writerequest: cred == NULL"));
|
||||||
|
crhold(cred);
|
||||||
|
mtx_unlock(&ktrace_mtx);
|
||||||
|
|
||||||
kth = &req->ktr_header;
|
kth = &req->ktr_header;
|
||||||
datalen = data_lengths[(u_short)kth->ktr_type & ~KTR_DROP];
|
datalen = data_lengths[(u_short)kth->ktr_type & ~KTR_DROP];
|
||||||
@ -963,18 +962,26 @@ ktr_writerequest(struct thread *td, struct ktr_request *req)
|
|||||||
error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, cred);
|
error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, cred);
|
||||||
VOP_UNLOCK(vp, 0);
|
VOP_UNLOCK(vp, 0);
|
||||||
vn_finished_write(mp);
|
vn_finished_write(mp);
|
||||||
vrele(vp);
|
crfree(cred);
|
||||||
VFS_UNLOCK_GIANT(vfslocked);
|
if (!error) {
|
||||||
if (!error)
|
vrele(vp);
|
||||||
|
VFS_UNLOCK_GIANT(vfslocked);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
VFS_UNLOCK_GIANT(vfslocked);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If error encountered, give up tracing on this vnode. We defer
|
* If error encountered, give up tracing on this vnode. We defer
|
||||||
* all the vrele()'s on the vnode until after we are finished walking
|
* all the vrele()'s on the vnode until after we are finished walking
|
||||||
* the various lists to avoid needlessly holding locks.
|
* the various lists to avoid needlessly holding locks.
|
||||||
|
* NB: at this point we still hold the vnode reference that must
|
||||||
|
* not go away as we need the valid vnode to compare with. Thus let
|
||||||
|
* vrele_count start at 1 and the reference will be freed
|
||||||
|
* by the loop at the end after our last use of vp.
|
||||||
*/
|
*/
|
||||||
log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
|
log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
|
||||||
error);
|
error);
|
||||||
vrele_count = 0;
|
vrele_count = 1;
|
||||||
/*
|
/*
|
||||||
* First, clear this vnode from being used by any processes in the
|
* First, clear this vnode from being used by any processes in the
|
||||||
* system.
|
* system.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user