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 | |
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
-rw-r--r-- | sys/compat/svr4/svr4_stream.c | 20 | ||||
-rw-r--r-- | sys/kern/kern_ktrace.c | 64 | ||||
-rw-r--r-- | sys/kern/sys_generic.c | 51 | ||||
-rw-r--r-- | sys/kern/uipc_syscalls.c | 20 | ||||
-rw-r--r-- | sys/svr4/svr4_stream.c | 20 | ||||
-rw-r--r-- | sys/sys/ktrace.h | 2 |
6 files changed, 108 insertions, 69 deletions
diff --git a/sys/compat/svr4/svr4_stream.c b/sys/compat/svr4/svr4_stream.c index a4cd74f..b2cadc9 100644 --- a/sys/compat/svr4/svr4_stream.c +++ b/sys/compat/svr4/svr4_stream.c @@ -159,6 +159,7 @@ svr4_sendit(p, s, mp, flags) struct socket *so; #ifdef KTRACE struct iovec *ktriov = NULL; + struct uio ktruio; #endif error = getsock(p->p_fd, s, &fp); @@ -199,6 +200,7 @@ svr4_sendit(p, s, mp, flags) MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); + ktruio = auio; } #endif len = auio.uio_resid; @@ -216,9 +218,11 @@ svr4_sendit(p, s, mp, flags) p->p_retval[0] = len - auio.uio_resid; #ifdef KTRACE if (ktriov != NULL) { - if (error == 0) - ktrgenio(p->p_tracep, s, UIO_WRITE, - ktriov, p->p_retval[0], error); + if (error == 0) { + ktruio.uio_iov = ktriov; + ktruio.uio_resid = p->p_retval[0]; + ktrgenio(p->p_tracep, s, UIO_WRITE, &ktruio, error); + } FREE(ktriov, M_TEMP); } #endif @@ -246,6 +250,7 @@ svr4_recvit(p, s, mp, namelenp) struct sockaddr *fromsa = 0; #ifdef KTRACE struct iovec *ktriov = NULL; + struct uio ktruio; #endif error = getsock(p->p_fd, s, &fp); @@ -269,6 +274,7 @@ svr4_recvit(p, s, mp, namelenp) MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); + ktruio = auio; } #endif len = auio.uio_resid; @@ -283,9 +289,11 @@ svr4_recvit(p, s, mp, namelenp) } #ifdef KTRACE if (ktriov != NULL) { - if (error == 0) - ktrgenio(p->p_tracep, s, UIO_READ, - ktriov, len - auio.uio_resid, error); + if (error == 0) { + ktruio.uio_iov = ktriov; + ktruio.uio_resid = len - auio.uio_resid; + ktrgenio(p->p_tracep, s, UIO_READ, &ktruio, error); + } FREE(ktriov, M_TEMP); } #endif 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; diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index bf33a4d..562536a 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -154,6 +154,7 @@ dofileread(p, fp, fd, buf, nbyte, offset, flags) long cnt, error = 0; #ifdef KTRACE struct iovec ktriov; + struct uio ktruio; #endif aiov.iov_base = (caddr_t)buf; @@ -171,8 +172,10 @@ dofileread(p, fp, fd, buf, nbyte, offset, flags) /* * if tracing, save a copy of iovec */ - if (KTRPOINT(p, KTR_GENIO)) + if (KTRPOINT(p, KTR_GENIO)) { ktriov = aiov; + ktruio = auio; + } #endif cnt = nbyte; if ((error = fo_read(fp, &auio, fp->f_cred, flags, p))) @@ -181,8 +184,11 @@ dofileread(p, fp, fd, buf, nbyte, offset, flags) error = 0; cnt -= auio.uio_resid; #ifdef KTRACE - if (KTRPOINT(p, KTR_GENIO) && error == 0) - ktrgenio(p->p_tracep, fd, UIO_READ, &ktriov, cnt, error); + if (error == 0 && KTRPOINT(p, KTR_GENIO)) { + ktruio.uio_iov = &ktriov; + ktruio.uio_resid = cnt; + ktrgenio(p->p_tracep, fd, UIO_READ, &ktruio, error); + } #endif p->p_retval[0] = cnt; return (error); @@ -213,6 +219,7 @@ readv(p, uap) u_int iovlen; #ifdef KTRACE struct iovec *ktriov = NULL; + struct uio ktruio; #endif if ((fp = getfp(fdp, uap->fd, FREAD)) == NULL) @@ -252,6 +259,7 @@ readv(p, uap) if (KTRPOINT(p, KTR_GENIO)) { MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); + ktruio = auio; } #endif cnt = auio.uio_resid; @@ -262,9 +270,12 @@ readv(p, uap) cnt -= auio.uio_resid; #ifdef KTRACE if (ktriov != NULL) { - if (error == 0) - ktrgenio(p->p_tracep, uap->fd, UIO_READ, ktriov, - cnt, error); + if (error == 0) { + ktruio.uio_iov = ktriov; + ktruio.uio_resid = cnt; + ktrgenio(p->p_tracep, uap->fd, UIO_READ, &ktruio, + error); + } FREE(ktriov, M_TEMP); } #endif @@ -338,6 +349,7 @@ dofilewrite(p, fp, fd, buf, nbyte, offset, flags) long cnt, error = 0; #ifdef KTRACE struct iovec ktriov; + struct uio ktruio; #endif aiov.iov_base = (void *)buf; @@ -353,10 +365,12 @@ dofilewrite(p, fp, fd, buf, nbyte, offset, flags) auio.uio_procp = p; #ifdef KTRACE /* - * if tracing, save a copy of iovec + * if tracing, save a copy of iovec and uio */ - if (KTRPOINT(p, KTR_GENIO)) + if (KTRPOINT(p, KTR_GENIO)) { ktriov = aiov; + ktruio = auio; + } #endif cnt = nbyte; if ((error = fo_write(fp, &auio, fp->f_cred, flags, p))) { @@ -368,9 +382,11 @@ dofilewrite(p, fp, fd, buf, nbyte, offset, flags) } cnt -= auio.uio_resid; #ifdef KTRACE - if (KTRPOINT(p, KTR_GENIO) && error == 0) - ktrgenio(p->p_tracep, fd, UIO_WRITE, - &ktriov, cnt, error); + if (error == 0 && KTRPOINT(p, KTR_GENIO)) { + ktruio.uio_iov = &ktriov; + ktruio.uio_resid = cnt; + ktrgenio(p->p_tracep, fd, UIO_WRITE, &ktruio, error); + } #endif p->p_retval[0] = cnt; return (error); @@ -401,6 +417,7 @@ writev(p, uap) u_int iovlen; #ifdef KTRACE struct iovec *ktriov = NULL; + struct uio ktruio; #endif if ((fp = getfp(fdp, uap->fd, FWRITE)) == NULL) @@ -439,11 +456,12 @@ writev(p, uap) } #ifdef KTRACE /* - * if tracing, save a copy of iovec + * if tracing, save a copy of iovec and uio */ if (KTRPOINT(p, KTR_GENIO)) { MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); + ktruio = auio; } #endif cnt = auio.uio_resid; @@ -457,9 +475,12 @@ writev(p, uap) cnt -= auio.uio_resid; #ifdef KTRACE if (ktriov != NULL) { - if (error == 0) - ktrgenio(p->p_tracep, uap->fd, UIO_WRITE, - ktriov, cnt, error); + if (error == 0) { + ktruio.uio_iov = ktriov; + ktruio.uio_resid = cnt; + ktrgenio(p->p_tracep, uap->fd, UIO_WRITE, &ktruio, + error); + } FREE(ktriov, M_TEMP); } #endif diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 480b8dc..5ba2a24 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -451,6 +451,7 @@ sendit(p, s, mp, flags) struct socket *so; #ifdef KTRACE struct iovec *ktriov = NULL; + struct uio ktruio; #endif error = getsock(p->p_fd, s, &fp); @@ -511,6 +512,7 @@ sendit(p, s, mp, flags) MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); + ktruio = auio; } #endif len = auio.uio_resid; @@ -528,9 +530,11 @@ sendit(p, s, mp, flags) p->p_retval[0] = len - auio.uio_resid; #ifdef KTRACE if (ktriov != NULL) { - if (error == 0) - ktrgenio(p->p_tracep, s, UIO_WRITE, - ktriov, p->p_retval[0], error); + if (error == 0) { + ktruio.uio_iov = ktriov; + ktruio.uio_resid = p->p_retval[0]; + ktrgenio(p->p_tracep, s, UIO_WRITE, &ktruio, error); + } FREE(ktriov, M_TEMP); } #endif @@ -688,6 +692,7 @@ recvit(p, s, mp, namelenp) struct sockaddr *fromsa = 0; #ifdef KTRACE struct iovec *ktriov = NULL; + struct uio ktruio; #endif error = getsock(p->p_fd, s, &fp); @@ -711,6 +716,7 @@ recvit(p, s, mp, namelenp) MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); + ktruio = auio; } #endif len = auio.uio_resid; @@ -725,9 +731,11 @@ recvit(p, s, mp, namelenp) } #ifdef KTRACE if (ktriov != NULL) { - if (error == 0) - ktrgenio(p->p_tracep, s, UIO_READ, - ktriov, len - auio.uio_resid, error); + if (error == 0) { + ktruio.uio_iov = ktriov; + ktruio.uio_resid = len - auio.uio_resid; + ktrgenio(p->p_tracep, s, UIO_READ, &ktruio, error); + } FREE(ktriov, M_TEMP); } #endif diff --git a/sys/svr4/svr4_stream.c b/sys/svr4/svr4_stream.c index a4cd74f..b2cadc9 100644 --- a/sys/svr4/svr4_stream.c +++ b/sys/svr4/svr4_stream.c @@ -159,6 +159,7 @@ svr4_sendit(p, s, mp, flags) struct socket *so; #ifdef KTRACE struct iovec *ktriov = NULL; + struct uio ktruio; #endif error = getsock(p->p_fd, s, &fp); @@ -199,6 +200,7 @@ svr4_sendit(p, s, mp, flags) MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); + ktruio = auio; } #endif len = auio.uio_resid; @@ -216,9 +218,11 @@ svr4_sendit(p, s, mp, flags) p->p_retval[0] = len - auio.uio_resid; #ifdef KTRACE if (ktriov != NULL) { - if (error == 0) - ktrgenio(p->p_tracep, s, UIO_WRITE, - ktriov, p->p_retval[0], error); + if (error == 0) { + ktruio.uio_iov = ktriov; + ktruio.uio_resid = p->p_retval[0]; + ktrgenio(p->p_tracep, s, UIO_WRITE, &ktruio, error); + } FREE(ktriov, M_TEMP); } #endif @@ -246,6 +250,7 @@ svr4_recvit(p, s, mp, namelenp) struct sockaddr *fromsa = 0; #ifdef KTRACE struct iovec *ktriov = NULL; + struct uio ktruio; #endif error = getsock(p->p_fd, s, &fp); @@ -269,6 +274,7 @@ svr4_recvit(p, s, mp, namelenp) MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK); bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen); + ktruio = auio; } #endif len = auio.uio_resid; @@ -283,9 +289,11 @@ svr4_recvit(p, s, mp, namelenp) } #ifdef KTRACE if (ktriov != NULL) { - if (error == 0) - ktrgenio(p->p_tracep, s, UIO_READ, - ktriov, len - auio.uio_resid, error); + if (error == 0) { + ktruio.uio_iov = ktriov; + ktruio.uio_resid = len - auio.uio_resid; + ktrgenio(p->p_tracep, s, UIO_READ, &ktruio, error); + } FREE(ktriov, M_TEMP); } #endif diff --git a/sys/sys/ktrace.h b/sys/sys/ktrace.h index 3804937..a6a2442 100644 --- a/sys/sys/ktrace.h +++ b/sys/sys/ktrace.h @@ -160,7 +160,7 @@ struct ktr_csw { void ktrnamei __P((struct vnode *,char *)); void ktrcsw __P((struct vnode *,int,int)); void ktrpsig __P((struct vnode *, int, sig_t, sigset_t *, int)); -void ktrgenio __P((struct vnode *,int, enum uio_rw,struct iovec *,int,int)); +void ktrgenio __P((struct vnode *, int, enum uio_rw, struct uio *, int)); void ktrsyscall __P((struct vnode *, int, int narg, register_t args[])); void ktrsysret __P((struct vnode *, int, int, register_t)); |