summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/kern_exec.c10
-rw-r--r--sys/kern/kern_exit.c7
-rw-r--r--sys/kern/kern_fork.c7
-rw-r--r--sys/kern/kern_ktrace.c59
4 files changed, 66 insertions, 17 deletions
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 32df1c2..0e5fb94 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -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.
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 25cc147..0793503 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -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.
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 592ff44..2d1ce60 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -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);
diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c
index 6297f9b..db44873 100644
--- a/sys/kern/kern_ktrace.c
+++ b/sys/kern/kern_ktrace.c
@@ -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);
OpenPOWER on IntegriCloud