136359Smarc /* 263174Sbostic * Copyright (c) 1989, 1993 363174Sbostic * The Regents of the University of California. All rights reserved. 436359Smarc * 544436Sbostic * %sccs.include.redist.c% 636359Smarc * 7*68329Scgd * @(#)kern_ktrace.c 8.4 (Berkeley) 02/14/95 836359Smarc */ 936359Smarc 1036359Smarc #ifdef KTRACE 1136359Smarc 1256517Sbostic #include <sys/param.h> 13*68329Scgd #include <sys/systm.h> 1456517Sbostic #include <sys/proc.h> 1556517Sbostic #include <sys/file.h> 1656517Sbostic #include <sys/namei.h> 1756517Sbostic #include <sys/vnode.h> 1856517Sbostic #include <sys/ktrace.h> 1956517Sbostic #include <sys/malloc.h> 2056517Sbostic #include <sys/syslog.h> 2136359Smarc 22*68329Scgd #include <sys/mount.h> 23*68329Scgd #include <sys/syscallargs.h> 24*68329Scgd 2536359Smarc struct ktr_header * 2636359Smarc ktrgetheader(type) 2760514Storek int type; 2836359Smarc { 2936359Smarc register struct ktr_header *kth; 3048017Smckusick struct proc *p = curproc; /* XXX */ 3136359Smarc 3236359Smarc MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 3336359Smarc M_TEMP, M_WAITOK); 3436359Smarc kth->ktr_type = type; 3537593Smarc microtime(&kth->ktr_time); 3647548Skarels kth->ktr_pid = p->p_pid; 3747548Skarels bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN); 3836359Smarc return (kth); 3936359Smarc } 4036359Smarc 41*68329Scgd void 42*68329Scgd ktrsyscall(vp, code, argsize, args) 4337728Smckusick struct vnode *vp; 44*68329Scgd int code, argsize; 45*68329Scgd register_t args[]; 4636359Smarc { 4753012Smarc struct ktr_header *kth; 4836359Smarc struct ktr_syscall *ktp; 49*68329Scgd register len = sizeof(struct ktr_syscall) + argsize; 5053012Smarc struct proc *p = curproc; /* XXX */ 51*68329Scgd register_t *argp; 52*68329Scgd int i; 5336359Smarc 5453012Smarc p->p_traceflag |= KTRFAC_ACTIVE; 5553012Smarc kth = ktrgetheader(KTR_SYSCALL); 5636359Smarc MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); 5736359Smarc ktp->ktr_code = code; 58*68329Scgd ktp->ktr_argsize = argsize; 59*68329Scgd argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall)); 60*68329Scgd for (i = 0; i < (argsize / sizeof *argp); i++) 6143444Smckusick *argp++ = args[i]; 6236359Smarc kth->ktr_buf = (caddr_t)ktp; 6336359Smarc kth->ktr_len = len; 6437728Smckusick ktrwrite(vp, kth); 6536359Smarc FREE(ktp, M_TEMP); 6636359Smarc FREE(kth, M_TEMP); 6753012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE; 6836359Smarc } 6936359Smarc 70*68329Scgd void 7143444Smckusick ktrsysret(vp, code, error, retval) 7237728Smckusick struct vnode *vp; 7343444Smckusick int code, error, retval; 7436359Smarc { 7553012Smarc struct ktr_header *kth; 7640805Smarc struct ktr_sysret ktp; 7753012Smarc struct proc *p = curproc; /* XXX */ 7836359Smarc 7953012Smarc p->p_traceflag |= KTRFAC_ACTIVE; 8053012Smarc kth = ktrgetheader(KTR_SYSRET); 8140805Smarc ktp.ktr_code = code; 8243444Smckusick ktp.ktr_error = error; 8343444Smckusick ktp.ktr_retval = retval; /* what about val2 ? */ 8436359Smarc 8540805Smarc kth->ktr_buf = (caddr_t)&ktp; 8636359Smarc kth->ktr_len = sizeof(struct ktr_sysret); 8736359Smarc 8837728Smckusick ktrwrite(vp, kth); 8936359Smarc FREE(kth, M_TEMP); 9053012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE; 9136359Smarc } 9236359Smarc 93*68329Scgd void 9437728Smckusick ktrnamei(vp, path) 9537728Smckusick struct vnode *vp; 9636359Smarc char *path; 9736359Smarc { 9853012Smarc struct ktr_header *kth; 9953012Smarc struct proc *p = curproc; /* XXX */ 10036359Smarc 10153012Smarc p->p_traceflag |= KTRFAC_ACTIVE; 10253012Smarc kth = ktrgetheader(KTR_NAMEI); 10336359Smarc kth->ktr_len = strlen(path); 10436359Smarc kth->ktr_buf = path; 10536359Smarc 10637728Smckusick ktrwrite(vp, kth); 10736359Smarc FREE(kth, M_TEMP); 10853012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE; 10936359Smarc } 11036359Smarc 111*68329Scgd void 11243444Smckusick ktrgenio(vp, fd, rw, iov, len, error) 11337728Smckusick struct vnode *vp; 11443444Smckusick int fd; 11537593Smarc enum uio_rw rw; 11637593Smarc register struct iovec *iov; 11760514Storek int len, error; 11837593Smarc { 11953012Smarc struct ktr_header *kth; 12037593Smarc register struct ktr_genio *ktp; 12137593Smarc register caddr_t cp; 12237593Smarc register int resid = len, cnt; 12353012Smarc struct proc *p = curproc; /* XXX */ 12437593Smarc 12546424Smarc if (error) 12637593Smarc return; 12753012Smarc p->p_traceflag |= KTRFAC_ACTIVE; 12853012Smarc kth = ktrgetheader(KTR_GENIO); 12937593Smarc MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, 13037593Smarc M_TEMP, M_WAITOK); 13137593Smarc ktp->ktr_fd = fd; 13237593Smarc ktp->ktr_rw = rw; 13337593Smarc cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); 13437593Smarc while (resid > 0) { 13537593Smarc if ((cnt = iov->iov_len) > resid) 13637593Smarc cnt = resid; 13741573Smckusick if (copyin(iov->iov_base, cp, (unsigned)cnt)) 13837593Smarc goto done; 13937593Smarc cp += cnt; 14037593Smarc resid -= cnt; 14137593Smarc iov++; 14237593Smarc } 14337593Smarc kth->ktr_buf = (caddr_t)ktp; 14437593Smarc kth->ktr_len = sizeof (struct ktr_genio) + len; 14537593Smarc 14637728Smckusick ktrwrite(vp, kth); 14737593Smarc done: 14837593Smarc FREE(kth, M_TEMP); 14937593Smarc FREE(ktp, M_TEMP); 15053012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE; 15137593Smarc } 15237593Smarc 153*68329Scgd void 15440805Smarc ktrpsig(vp, sig, action, mask, code) 15560514Storek struct vnode *vp; 15660514Storek int sig; 15760514Storek sig_t action; 15860514Storek int mask, code; 15940805Smarc { 16053012Smarc struct ktr_header *kth; 16140805Smarc struct ktr_psig kp; 16253012Smarc struct proc *p = curproc; /* XXX */ 16340805Smarc 16453012Smarc p->p_traceflag |= KTRFAC_ACTIVE; 16553012Smarc kth = ktrgetheader(KTR_PSIG); 16640805Smarc kp.signo = (char)sig; 16740805Smarc kp.action = action; 16840805Smarc kp.mask = mask; 16940805Smarc kp.code = code; 17040805Smarc kth->ktr_buf = (caddr_t)&kp; 17140805Smarc kth->ktr_len = sizeof (struct ktr_psig); 17240805Smarc 17340805Smarc ktrwrite(vp, kth); 17440805Smarc FREE(kth, M_TEMP); 17553012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE; 17640805Smarc } 17740805Smarc 178*68329Scgd void 17953012Smarc ktrcsw(vp, out, user) 18060514Storek struct vnode *vp; 18160514Storek int out, user; 18253012Smarc { 18353012Smarc struct ktr_header *kth; 18453012Smarc struct ktr_csw kc; 18553012Smarc struct proc *p = curproc; /* XXX */ 18653012Smarc 18753012Smarc p->p_traceflag |= KTRFAC_ACTIVE; 18853012Smarc kth = ktrgetheader(KTR_CSW); 18953012Smarc kc.out = out; 19053012Smarc kc.user = user; 19153012Smarc kth->ktr_buf = (caddr_t)&kc; 19253012Smarc kth->ktr_len = sizeof (struct ktr_csw); 19353012Smarc 19453012Smarc ktrwrite(vp, kth); 19553012Smarc FREE(kth, M_TEMP); 19653012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE; 19753012Smarc } 19853012Smarc 19940805Smarc /* Interface and common routines */ 20040805Smarc 20136359Smarc /* 20236359Smarc * ktrace system call 20336359Smarc */ 20443444Smckusick /* ARGSUSED */ 205*68329Scgd int 20643444Smckusick ktrace(curp, uap, retval) 20743444Smckusick struct proc *curp; 208*68329Scgd register struct ktrace_args /* { 209*68329Scgd syscallarg(char *) fname; 210*68329Scgd syscallarg(int) ops; 211*68329Scgd syscallarg(int) facs; 212*68329Scgd syscallarg(int) pid; 213*68329Scgd } */ *uap; 214*68329Scgd register_t *retval; 21543444Smckusick { 21637728Smckusick register struct vnode *vp = NULL; 21736359Smarc register struct proc *p; 21836359Smarc struct pgrp *pg; 219*68329Scgd int facs = SCARG(uap, facs) & ~KTRFAC_ROOT; 220*68329Scgd int ops = KTROP(SCARG(uap, ops)); 221*68329Scgd int descend = SCARG(uap, ops) & KTRFLAG_DESCEND; 22246424Smarc int ret = 0; 22343444Smckusick int error = 0; 22447548Skarels struct nameidata nd; 22536359Smarc 22653012Smarc curp->p_traceflag |= KTRFAC_ACTIVE; 22736359Smarc if (ops != KTROP_CLEAR) { 22836359Smarc /* 22936359Smarc * an operation which requires a file argument. 23036359Smarc */ 231*68329Scgd NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname), 232*68329Scgd curp); 23353012Smarc if (error = vn_open(&nd, FREAD|FWRITE, 0)) { 23453012Smarc curp->p_traceflag &= ~KTRFAC_ACTIVE; 23544404Skarels return (error); 23653012Smarc } 23747548Skarels vp = nd.ni_vp; 23849914Smckusick VOP_UNLOCK(vp); 23937728Smckusick if (vp->v_type != VREG) { 24050106Smckusick (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp); 24153012Smarc curp->p_traceflag &= ~KTRFAC_ACTIVE; 24244404Skarels return (EACCES); 24336359Smarc } 24436359Smarc } 24536359Smarc /* 24636359Smarc * Clear all uses of the tracefile 24736359Smarc */ 24836359Smarc if (ops == KTROP_CLEARFILE) { 24967732Smckusick for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 25037728Smckusick if (p->p_tracep == vp) { 25146424Smarc if (ktrcanset(curp, p)) { 25246424Smarc p->p_tracep = NULL; 25346424Smarc p->p_traceflag = 0; 25450106Smckusick (void) vn_close(vp, FREAD|FWRITE, 25550106Smckusick p->p_ucred, p); 25646424Smarc } else 25746424Smarc error = EPERM; 25836359Smarc } 25936359Smarc } 26036359Smarc goto done; 26136359Smarc } 26236359Smarc /* 26346424Smarc * need something to (un)trace (XXX - why is this here?) 26436359Smarc */ 26536359Smarc if (!facs) { 26643444Smckusick error = EINVAL; 26736359Smarc goto done; 26836359Smarc } 26940805Smarc /* 27046424Smarc * do it 27140805Smarc */ 272*68329Scgd if (SCARG(uap, pid) < 0) { 27346424Smarc /* 27446424Smarc * by process group 27546424Smarc */ 276*68329Scgd pg = pgfind(-SCARG(uap, pid)); 27736359Smarc if (pg == NULL) { 27843444Smckusick error = ESRCH; 27936359Smarc goto done; 28036359Smarc } 28167732Smckusick for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) 28246424Smarc if (descend) 28346424Smarc ret |= ktrsetchildren(curp, p, ops, facs, vp); 28436359Smarc else 28546424Smarc ret |= ktrops(curp, p, ops, facs, vp); 28636359Smarc 28736359Smarc } else { 28846424Smarc /* 28946424Smarc * by pid 29046424Smarc */ 291*68329Scgd p = pfind(SCARG(uap, pid)); 29236359Smarc if (p == NULL) { 29343444Smckusick error = ESRCH; 29436359Smarc goto done; 29536359Smarc } 29646424Smarc if (descend) 29746424Smarc ret |= ktrsetchildren(curp, p, ops, facs, vp); 29836359Smarc else 29946424Smarc ret |= ktrops(curp, p, ops, facs, vp); 30036359Smarc } 30137593Smarc if (!ret) 30243444Smckusick error = EPERM; 30336359Smarc done: 30437728Smckusick if (vp != NULL) 30550106Smckusick (void) vn_close(vp, FWRITE, curp->p_ucred, curp); 30653012Smarc curp->p_traceflag &= ~KTRFAC_ACTIVE; 30744404Skarels return (error); 30836359Smarc } 30936359Smarc 31060514Storek int 31146424Smarc ktrops(curp, p, ops, facs, vp) 31260514Storek struct proc *p, *curp; 31360514Storek int ops, facs; 31437728Smckusick struct vnode *vp; 31536359Smarc { 31637593Smarc 31746424Smarc if (!ktrcanset(curp, p)) 31844404Skarels return (0); 31936359Smarc if (ops == KTROP_SET) { 32040805Smarc if (p->p_tracep != vp) { 32136359Smarc /* 32236359Smarc * if trace file already in use, relinquish 32336359Smarc */ 32436359Smarc if (p->p_tracep != NULL) 32537728Smckusick vrele(p->p_tracep); 32638423Smarc VREF(vp); 32737728Smckusick p->p_tracep = vp; 32836359Smarc } 32936359Smarc p->p_traceflag |= facs; 33047548Skarels if (curp->p_ucred->cr_uid == 0) 33146424Smarc p->p_traceflag |= KTRFAC_ROOT; 33236359Smarc } else { 33336359Smarc /* KTROP_CLEAR */ 33446424Smarc if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { 33540805Smarc /* no more tracing */ 33640805Smarc p->p_traceflag = 0; 33736359Smarc if (p->p_tracep != NULL) { 33837728Smckusick vrele(p->p_tracep); 33936359Smarc p->p_tracep = NULL; 34036359Smarc } 34136359Smarc } 34236359Smarc } 34337593Smarc 34446424Smarc return (1); 34536359Smarc } 34637593Smarc 34746424Smarc ktrsetchildren(curp, top, ops, facs, vp) 34846424Smarc struct proc *curp, *top; 34960514Storek int ops, facs; 35037728Smckusick struct vnode *vp; 35136359Smarc { 35236359Smarc register struct proc *p; 35337593Smarc register int ret = 0; 35436359Smarc 35536359Smarc p = top; 35636359Smarc for (;;) { 35746424Smarc ret |= ktrops(curp, p, ops, facs, vp); 35836359Smarc /* 35936359Smarc * If this process has children, descend to them next, 36036359Smarc * otherwise do any siblings, and if done with this level, 36136359Smarc * follow back up the tree (but not past top). 36236359Smarc */ 36367732Smckusick if (p->p_children.lh_first) 36467732Smckusick p = p->p_children.lh_first; 36536359Smarc else for (;;) { 36636359Smarc if (p == top) 36746424Smarc return (ret); 36867732Smckusick if (p->p_sibling.le_next) { 36967732Smckusick p = p->p_sibling.le_next; 37036359Smarc break; 37136359Smarc } 37267732Smckusick p = p->p_pptr; 37336359Smarc } 37436359Smarc } 37537593Smarc /*NOTREACHED*/ 37636359Smarc } 37736359Smarc 37837728Smckusick ktrwrite(vp, kth) 37937728Smckusick struct vnode *vp; 38037728Smckusick register struct ktr_header *kth; 38136359Smarc { 38237728Smckusick struct uio auio; 38337728Smckusick struct iovec aiov[2]; 38448017Smckusick register struct proc *p = curproc; /* XXX */ 38539581Smckusick int error; 38637728Smckusick 38737728Smckusick if (vp == NULL) 38837593Smarc return; 38937728Smckusick auio.uio_iov = &aiov[0]; 39037728Smckusick auio.uio_offset = 0; 39137728Smckusick auio.uio_segflg = UIO_SYSSPACE; 39237728Smckusick auio.uio_rw = UIO_WRITE; 39337728Smckusick aiov[0].iov_base = (caddr_t)kth; 39437728Smckusick aiov[0].iov_len = sizeof(struct ktr_header); 39537728Smckusick auio.uio_resid = sizeof(struct ktr_header); 39637728Smckusick auio.uio_iovcnt = 1; 39748017Smckusick auio.uio_procp = (struct proc *)0; 39836359Smarc if (kth->ktr_len > 0) { 39937728Smckusick auio.uio_iovcnt++; 40037728Smckusick aiov[1].iov_base = kth->ktr_buf; 40137728Smckusick aiov[1].iov_len = kth->ktr_len; 40237728Smckusick auio.uio_resid += kth->ktr_len; 40336359Smarc } 40439581Smckusick VOP_LOCK(vp); 40548017Smckusick error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred); 40639581Smckusick VOP_UNLOCK(vp); 40741573Smckusick if (!error) 40841573Smckusick return; 40941573Smckusick /* 41041573Smckusick * If error encountered, give up tracing on this vnode. 41141573Smckusick */ 41247548Skarels log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", 41347548Skarels error); 41467732Smckusick for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 41541573Smckusick if (p->p_tracep == vp) { 41641573Smckusick p->p_tracep = NULL; 41741573Smckusick p->p_traceflag = 0; 41841573Smckusick vrele(vp); 41941573Smckusick } 42041573Smckusick } 42136359Smarc } 42246424Smarc 42346424Smarc /* 42446424Smarc * Return true if caller has permission to set the ktracing state 42546424Smarc * of target. Essentially, the target can't possess any 42646424Smarc * more permissions than the caller. KTRFAC_ROOT signifies that 42746424Smarc * root previously set the tracing status on the target process, and 42846424Smarc * so, only root may further change it. 42946424Smarc * 43047548Skarels * TODO: check groups. use caller effective gid. 43146424Smarc */ 43247548Skarels ktrcanset(callp, targetp) 43347548Skarels struct proc *callp, *targetp; 43446424Smarc { 43547548Skarels register struct pcred *caller = callp->p_cred; 43647548Skarels register struct pcred *target = targetp->p_cred; 43747548Skarels 43847548Skarels if ((caller->pc_ucred->cr_uid == target->p_ruid && 43946424Smarc target->p_ruid == target->p_svuid && 44046424Smarc caller->p_rgid == target->p_rgid && /* XXX */ 44146424Smarc target->p_rgid == target->p_svgid && 44247548Skarels (targetp->p_traceflag & KTRFAC_ROOT) == 0) || 44347548Skarels caller->pc_ucred->cr_uid == 0) 44446424Smarc return (1); 44546424Smarc 44646424Smarc return (0); 44746424Smarc } 44846424Smarc 44936359Smarc #endif 450