diff options
author | green <green@FreeBSD.org> | 2000-07-02 08:08:09 +0000 |
---|---|---|
committer | green <green@FreeBSD.org> | 2000-07-02 08:08:09 +0000 |
commit | 9707bc34b009d1e09d192ec84d1ddc8e8693006f (patch) | |
tree | 176c788b7d732a310aa42a0b4652b645bc735a99 /sys/kern/kern_ktrace.c | |
parent | c350a86095dd249ad9e0371c7caaf6a5c52a0260 (diff) | |
download | FreeBSD-src-9707bc34b009d1e09d192ec84d1ddc8e8693006f.zip FreeBSD-src-9707bc34b009d1e09d192ec84d1ddc8e8693006f.tar.gz |
Modify ktrace's general I/O tracing, ktrgenio(), to use a struct uio *
instead of a struct iovec * array and int len. Get rid of stupidly trying
to allocate all of the memory and copyin()ing the entire iovec[], and
instead just do the proper VOP_WRITE() in ktrwrite() using a copy of
the struct uio that the syscall originally used.
This solves the DoS which could easily be performed; to work around the
DoS, one could also remove "options KTRACE" from the kernel. This is
a very strong MFC candidate for 4.1.
Found by: art@OpenBSD.org
Diffstat (limited to 'sys/kern/kern_ktrace.c')
-rw-r--r-- | sys/kern/kern_ktrace.c | 64 |
1 files changed, 29 insertions, 35 deletions
diff --git a/sys/kern/kern_ktrace.c b/sys/kern/kern_ktrace.c index 1ca4e34..22f04e0 100644 --- a/sys/kern/kern_ktrace.c +++ b/sys/kern/kern_ktrace.c @@ -56,7 +56,7 @@ static MALLOC_DEFINE(M_KTRACE, "KTRACE", "KTRACE"); #ifdef KTRACE static struct ktr_header *ktrgetheader __P((int type)); -static void ktrwrite __P((struct vnode *, struct ktr_header *)); +static void ktrwrite __P((struct vnode *, struct ktr_header *, struct uio *)); static int ktrcanset __P((struct proc *,struct proc *)); static int ktrsetchildren __P((struct proc *,struct proc *,int,int,struct vnode *)); static int ktrops __P((struct proc *,struct proc *,int,int,struct vnode *)); @@ -102,7 +102,7 @@ ktrsyscall(vp, code, narg, args) *argp++ = args[i]; kth->ktr_buf = (caddr_t)ktp; kth->ktr_len = len; - ktrwrite(vp, kth); + ktrwrite(vp, kth, NULL); FREE(ktp, M_KTRACE); FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; @@ -127,7 +127,7 @@ ktrsysret(vp, code, error, retval) kth->ktr_buf = (caddr_t)&ktp; kth->ktr_len = sizeof(struct ktr_sysret); - ktrwrite(vp, kth); + ktrwrite(vp, kth, NULL); FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } @@ -145,50 +145,36 @@ ktrnamei(vp, path) kth->ktr_len = strlen(path); kth->ktr_buf = path; - ktrwrite(vp, kth); + ktrwrite(vp, kth, NULL); FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } void -ktrgenio(vp, fd, rw, iov, len, error) +ktrgenio(vp, fd, rw, uio, error) struct vnode *vp; int fd; enum uio_rw rw; - register struct iovec *iov; - int len, error; + struct uio *uio; + int error; { struct ktr_header *kth; - register struct ktr_genio *ktp; - register caddr_t cp; - register int resid = len, cnt; + struct ktr_genio ktg; struct proc *p = curproc; /* XXX */ if (error) return; p->p_traceflag |= KTRFAC_ACTIVE; kth = ktrgetheader(KTR_GENIO); - MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, - M_KTRACE, M_WAITOK); - ktp->ktr_fd = fd; - ktp->ktr_rw = rw; - cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); - while (resid > 0) { - if ((cnt = iov->iov_len) > resid) - cnt = resid; - if (copyin(iov->iov_base, cp, (unsigned)cnt)) - goto done; - cp += cnt; - resid -= cnt; - iov++; - } - kth->ktr_buf = (caddr_t)ktp; - kth->ktr_len = sizeof (struct ktr_genio) + len; - - ktrwrite(vp, kth); -done: + ktg.ktr_fd = fd; + ktg.ktr_rw = rw; + kth->ktr_buf = (caddr_t)&ktg; + kth->ktr_len = sizeof(struct ktr_genio); + uio->uio_offset = 0; + uio->uio_rw = UIO_READ; + + ktrwrite(vp, kth, uio); FREE(kth, M_KTRACE); - FREE(ktp, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } @@ -213,7 +199,7 @@ ktrpsig(vp, sig, action, mask, code) kth->ktr_buf = (caddr_t)&kp; kth->ktr_len = sizeof (struct ktr_psig); - ktrwrite(vp, kth); + ktrwrite(vp, kth, NULL); FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } @@ -234,7 +220,7 @@ ktrcsw(vp, out, user) kth->ktr_buf = (caddr_t)&kc; kth->ktr_len = sizeof (struct ktr_csw); - ktrwrite(vp, kth); + ktrwrite(vp, kth, NULL); FREE(kth, M_KTRACE); p->p_traceflag &= ~KTRFAC_ACTIVE; } @@ -380,7 +366,7 @@ utrace(curp, uap) if (!copyin(uap->addr, cp, uap->len)) { kth->ktr_buf = cp; kth->ktr_len = uap->len; - ktrwrite(p->p_tracep, kth); + ktrwrite(p->p_tracep, kth, NULL); } FREE(kth, M_KTRACE); FREE(cp, M_KTRACE); @@ -463,9 +449,10 @@ ktrsetchildren(curp, top, ops, facs, vp) } static void -ktrwrite(vp, kth) +ktrwrite(vp, kth, uio) struct vnode *vp; register struct ktr_header *kth; + struct uio *uio; { struct uio auio; struct iovec aiov[2]; @@ -488,9 +475,16 @@ ktrwrite(vp, kth) aiov[1].iov_base = kth->ktr_buf; aiov[1].iov_len = kth->ktr_len; auio.uio_resid += kth->ktr_len; + if (uio != NULL) + kth->ktr_len += uio->uio_resid; } vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred); + (void)VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, p->p_ucred); + if (error == 0 && uio != NULL) { + (void)VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + error = VOP_WRITE(vp, uio, IO_UNIT | IO_APPEND, p->p_ucred); + } VOP_UNLOCK(vp, 0, p); if (!error) return; |