summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_ktrace.c
diff options
context:
space:
mode:
authorbz <bz@FreeBSD.org>2008-12-03 15:54:35 +0000
committerbz <bz@FreeBSD.org>2008-12-03 15:54:35 +0000
commit965b4db5a53dc91313fc82e2b4e0f213bb636644 (patch)
tree32ee6bcdca0f0dd7eb955928d3b8383577c1715d /sys/kern/kern_ktrace.c
parent053f34b10a81d31d5c2fa818253f06f227ef0d2a (diff)
downloadFreeBSD-src-965b4db5a53dc91313fc82e2b4e0f213bb636644.zip
FreeBSD-src-965b4db5a53dc91313fc82e2b4e0f213bb636644.tar.gz
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
Diffstat (limited to 'sys/kern/kern_ktrace.c')
-rw-r--r--sys/kern/kern_ktrace.c25
1 files changed, 16 insertions, 9 deletions
diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c
index c8e4451..f4304de 100644
--- a/sys/kern/kern_ktrace.c
+++ b/sys/kern/kern_ktrace.c
@@ -907,12 +907,7 @@ ktr_writerequest(struct thread *td, struct ktr_request *req)
*/
mtx_lock(&ktrace_mtx);
vp = td->td_proc->p_tracevp;
- if (vp != NULL)
- VREF(vp);
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
@@ -921,9 +916,13 @@ ktr_writerequest(struct thread *td, struct ktr_request *req)
*/
if (vp == NULL) {
KASSERT(cred == NULL, ("ktr_writerequest: cred != NULL"));
+ mtx_unlock(&ktrace_mtx);
return;
}
+ VREF(vp);
KASSERT(cred != NULL, ("ktr_writerequest: cred == NULL"));
+ crhold(cred);
+ mtx_unlock(&ktrace_mtx);
kth = &req->ktr_header;
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);
VOP_UNLOCK(vp, 0);
vn_finished_write(mp);
- vrele(vp);
- VFS_UNLOCK_GIANT(vfslocked);
- if (!error)
+ crfree(cred);
+ if (!error) {
+ vrele(vp);
+ VFS_UNLOCK_GIANT(vfslocked);
return;
+ }
+ VFS_UNLOCK_GIANT(vfslocked);
+
/*
* If error encountered, give up tracing on this vnode. We defer
* all the vrele()'s on the vnode until after we are finished walking
* 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",
error);
- vrele_count = 0;
+ vrele_count = 1;
/*
* First, clear this vnode from being used by any processes in the
* system.
OpenPOWER on IntegriCloud