136359Smarc /* 236359Smarc * Copyright (c) 1989 The Regents of the University of California. 336359Smarc * All rights reserved. 436359Smarc * 544436Sbostic * %sccs.include.redist.c% 636359Smarc * 7*54924Storek * @(#)kern_ktrace.c 7.20 (Berkeley) 07/10/92 836359Smarc */ 936359Smarc 1036359Smarc #ifdef KTRACE 1136359Smarc 1236359Smarc #include "param.h" 1336359Smarc #include "proc.h" 1437728Smckusick #include "file.h" 1548017Smckusick #include "namei.h" 1637728Smckusick #include "vnode.h" 1736359Smarc #include "ktrace.h" 1836359Smarc #include "malloc.h" 1946424Smarc #include "syslog.h" 2036359Smarc 2136359Smarc struct ktr_header * 2236359Smarc ktrgetheader(type) 2336359Smarc { 2436359Smarc register struct ktr_header *kth; 2548017Smckusick struct proc *p = curproc; /* XXX */ 2636359Smarc 2736359Smarc MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 2836359Smarc M_TEMP, M_WAITOK); 2936359Smarc kth->ktr_type = type; 3037593Smarc microtime(&kth->ktr_time); 3147548Skarels kth->ktr_pid = p->p_pid; 3247548Skarels bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN); 3336359Smarc return (kth); 3436359Smarc } 3536359Smarc 3643444Smckusick ktrsyscall(vp, code, narg, args) 3737728Smckusick struct vnode *vp; 3843444Smckusick int code, narg, args[]; 3936359Smarc { 4053012Smarc struct ktr_header *kth; 4136359Smarc struct ktr_syscall *ktp; 4236359Smarc register len = sizeof(struct ktr_syscall) + (narg * sizeof(int)); 4353012Smarc struct proc *p = curproc; /* XXX */ 4436359Smarc int *argp, i; 4536359Smarc 4653012Smarc p->p_traceflag |= KTRFAC_ACTIVE; 4753012Smarc kth = ktrgetheader(KTR_SYSCALL); 4836359Smarc MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); 4936359Smarc ktp->ktr_code = code; 5036359Smarc ktp->ktr_narg = narg; 5136359Smarc argp = (int *)((char *)ktp + sizeof(struct ktr_syscall)); 5236359Smarc for (i = 0; i < narg; i++) 5343444Smckusick *argp++ = args[i]; 5436359Smarc kth->ktr_buf = (caddr_t)ktp; 5536359Smarc kth->ktr_len = len; 5637728Smckusick ktrwrite(vp, kth); 5736359Smarc FREE(ktp, M_TEMP); 5836359Smarc FREE(kth, M_TEMP); 5953012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE; 6036359Smarc } 6136359Smarc 6243444Smckusick ktrsysret(vp, code, error, retval) 6337728Smckusick struct vnode *vp; 6443444Smckusick int code, error, retval; 6536359Smarc { 6653012Smarc struct ktr_header *kth; 6740805Smarc struct ktr_sysret ktp; 6853012Smarc struct proc *p = curproc; /* XXX */ 6936359Smarc 7053012Smarc p->p_traceflag |= KTRFAC_ACTIVE; 7153012Smarc kth = ktrgetheader(KTR_SYSRET); 7240805Smarc ktp.ktr_code = code; 7343444Smckusick ktp.ktr_error = error; 7443444Smckusick ktp.ktr_retval = retval; /* what about val2 ? */ 7536359Smarc 7640805Smarc kth->ktr_buf = (caddr_t)&ktp; 7736359Smarc kth->ktr_len = sizeof(struct ktr_sysret); 7836359Smarc 7937728Smckusick ktrwrite(vp, kth); 8036359Smarc FREE(kth, M_TEMP); 8153012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE; 8236359Smarc } 8336359Smarc 8437728Smckusick ktrnamei(vp, path) 8537728Smckusick struct vnode *vp; 8636359Smarc char *path; 8736359Smarc { 8853012Smarc struct ktr_header *kth; 8953012Smarc struct proc *p = curproc; /* XXX */ 9036359Smarc 9153012Smarc p->p_traceflag |= KTRFAC_ACTIVE; 9253012Smarc kth = ktrgetheader(KTR_NAMEI); 9336359Smarc kth->ktr_len = strlen(path); 9436359Smarc kth->ktr_buf = path; 9536359Smarc 9637728Smckusick ktrwrite(vp, kth); 9736359Smarc FREE(kth, M_TEMP); 9853012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE; 9936359Smarc } 10036359Smarc 10143444Smckusick ktrgenio(vp, fd, rw, iov, len, error) 10237728Smckusick struct vnode *vp; 10343444Smckusick int fd; 10437593Smarc enum uio_rw rw; 10537593Smarc register struct iovec *iov; 10637593Smarc { 10753012Smarc struct ktr_header *kth; 10837593Smarc register struct ktr_genio *ktp; 10937593Smarc register caddr_t cp; 11037593Smarc register int resid = len, cnt; 11153012Smarc struct proc *p = curproc; /* XXX */ 11237593Smarc 11346424Smarc if (error) 11437593Smarc return; 11553012Smarc p->p_traceflag |= KTRFAC_ACTIVE; 11653012Smarc kth = ktrgetheader(KTR_GENIO); 11737593Smarc MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, 11837593Smarc M_TEMP, M_WAITOK); 11937593Smarc ktp->ktr_fd = fd; 12037593Smarc ktp->ktr_rw = rw; 12137593Smarc cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); 12237593Smarc while (resid > 0) { 12337593Smarc if ((cnt = iov->iov_len) > resid) 12437593Smarc cnt = resid; 12541573Smckusick if (copyin(iov->iov_base, cp, (unsigned)cnt)) 12637593Smarc goto done; 12737593Smarc cp += cnt; 12837593Smarc resid -= cnt; 12937593Smarc iov++; 13037593Smarc } 13137593Smarc kth->ktr_buf = (caddr_t)ktp; 13237593Smarc kth->ktr_len = sizeof (struct ktr_genio) + len; 13337593Smarc 13437728Smckusick ktrwrite(vp, kth); 13537593Smarc done: 13637593Smarc FREE(kth, M_TEMP); 13737593Smarc FREE(ktp, M_TEMP); 13853012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE; 13937593Smarc } 14037593Smarc 14140805Smarc ktrpsig(vp, sig, action, mask, code) 14240805Smarc struct vnode *vp; 14340805Smarc sig_t action; 14440805Smarc { 14553012Smarc struct ktr_header *kth; 14640805Smarc struct ktr_psig kp; 14753012Smarc struct proc *p = curproc; /* XXX */ 14840805Smarc 14953012Smarc p->p_traceflag |= KTRFAC_ACTIVE; 15053012Smarc kth = ktrgetheader(KTR_PSIG); 15140805Smarc kp.signo = (char)sig; 15240805Smarc kp.action = action; 15340805Smarc kp.mask = mask; 15440805Smarc kp.code = code; 15540805Smarc kth->ktr_buf = (caddr_t)&kp; 15640805Smarc kth->ktr_len = sizeof (struct ktr_psig); 15740805Smarc 15840805Smarc ktrwrite(vp, kth); 15940805Smarc FREE(kth, M_TEMP); 16053012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE; 16140805Smarc } 16240805Smarc 16353012Smarc ktrcsw(vp, out, user) 16453012Smarc struct vnode *vp; 16553012Smarc int out, user; 16653012Smarc { 16753012Smarc struct ktr_header *kth; 16853012Smarc struct ktr_csw kc; 16953012Smarc struct proc *p = curproc; /* XXX */ 17053012Smarc 17153012Smarc p->p_traceflag |= KTRFAC_ACTIVE; 17253012Smarc kth = ktrgetheader(KTR_CSW); 17353012Smarc kc.out = out; 17453012Smarc kc.user = user; 17553012Smarc kth->ktr_buf = (caddr_t)&kc; 17653012Smarc kth->ktr_len = sizeof (struct ktr_csw); 17753012Smarc 17853012Smarc ktrwrite(vp, kth); 17953012Smarc FREE(kth, M_TEMP); 18053012Smarc p->p_traceflag &= ~KTRFAC_ACTIVE; 18153012Smarc } 18253012Smarc 18340805Smarc /* Interface and common routines */ 18440805Smarc 18536359Smarc /* 18636359Smarc * ktrace system call 18736359Smarc */ 188*54924Storek struct ktrace_args { 189*54924Storek char *fname; 190*54924Storek int ops; 191*54924Storek int facs; 192*54924Storek int pid; 193*54924Storek }; 19443444Smckusick /* ARGSUSED */ 19543444Smckusick ktrace(curp, uap, retval) 19643444Smckusick struct proc *curp; 197*54924Storek register struct ktrace_args *uap; 19843444Smckusick int *retval; 19943444Smckusick { 20037728Smckusick register struct vnode *vp = NULL; 20136359Smarc register struct proc *p; 20236359Smarc struct pgrp *pg; 20346424Smarc int facs = uap->facs & ~KTRFAC_ROOT; 20446424Smarc int ops = KTROP(uap->ops); 20546424Smarc int descend = uap->ops & KTRFLAG_DESCEND; 20646424Smarc int ret = 0; 20743444Smckusick int error = 0; 20847548Skarels struct nameidata nd; 20936359Smarc 21053012Smarc curp->p_traceflag |= KTRFAC_ACTIVE; 21136359Smarc if (ops != KTROP_CLEAR) { 21236359Smarc /* 21336359Smarc * an operation which requires a file argument. 21436359Smarc */ 21553012Smarc NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, curp); 21653012Smarc if (error = vn_open(&nd, FREAD|FWRITE, 0)) { 21753012Smarc curp->p_traceflag &= ~KTRFAC_ACTIVE; 21844404Skarels return (error); 21953012Smarc } 22047548Skarels vp = nd.ni_vp; 22149914Smckusick VOP_UNLOCK(vp); 22237728Smckusick if (vp->v_type != VREG) { 22350106Smckusick (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp); 22453012Smarc curp->p_traceflag &= ~KTRFAC_ACTIVE; 22544404Skarels return (EACCES); 22636359Smarc } 22736359Smarc } 22836359Smarc /* 22936359Smarc * Clear all uses of the tracefile 23036359Smarc */ 23136359Smarc if (ops == KTROP_CLEARFILE) { 23254757Storek for (p = (struct proc *)allproc; p != NULL; p = p->p_nxt) { 23337728Smckusick if (p->p_tracep == vp) { 23446424Smarc if (ktrcanset(curp, p)) { 23546424Smarc p->p_tracep = NULL; 23646424Smarc p->p_traceflag = 0; 23750106Smckusick (void) vn_close(vp, FREAD|FWRITE, 23850106Smckusick p->p_ucred, p); 23946424Smarc } else 24046424Smarc error = EPERM; 24136359Smarc } 24236359Smarc } 24336359Smarc goto done; 24436359Smarc } 24536359Smarc /* 24646424Smarc * need something to (un)trace (XXX - why is this here?) 24736359Smarc */ 24836359Smarc if (!facs) { 24943444Smckusick error = EINVAL; 25036359Smarc goto done; 25136359Smarc } 25240805Smarc /* 25346424Smarc * do it 25440805Smarc */ 25536359Smarc if (uap->pid < 0) { 25646424Smarc /* 25746424Smarc * by process group 25846424Smarc */ 25936359Smarc pg = pgfind(-uap->pid); 26036359Smarc if (pg == NULL) { 26143444Smckusick error = ESRCH; 26236359Smarc goto done; 26336359Smarc } 26436359Smarc for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) 26546424Smarc if (descend) 26646424Smarc ret |= ktrsetchildren(curp, p, ops, facs, vp); 26736359Smarc else 26846424Smarc ret |= ktrops(curp, p, ops, facs, vp); 26936359Smarc 27036359Smarc } else { 27146424Smarc /* 27246424Smarc * by pid 27346424Smarc */ 27436359Smarc p = pfind(uap->pid); 27536359Smarc if (p == NULL) { 27643444Smckusick error = ESRCH; 27736359Smarc goto done; 27836359Smarc } 27946424Smarc if (descend) 28046424Smarc ret |= ktrsetchildren(curp, p, ops, facs, vp); 28136359Smarc else 28246424Smarc ret |= ktrops(curp, p, ops, facs, vp); 28336359Smarc } 28437593Smarc if (!ret) 28543444Smckusick error = EPERM; 28636359Smarc done: 28737728Smckusick if (vp != NULL) 28850106Smckusick (void) vn_close(vp, FWRITE, curp->p_ucred, curp); 28953012Smarc curp->p_traceflag &= ~KTRFAC_ACTIVE; 29044404Skarels return (error); 29136359Smarc } 29236359Smarc 29346424Smarc ktrops(curp, p, ops, facs, vp) 29446424Smarc struct proc *curp, *p; 29537728Smckusick struct vnode *vp; 29636359Smarc { 29737593Smarc 29846424Smarc if (!ktrcanset(curp, p)) 29944404Skarels return (0); 30036359Smarc if (ops == KTROP_SET) { 30140805Smarc if (p->p_tracep != vp) { 30236359Smarc /* 30336359Smarc * if trace file already in use, relinquish 30436359Smarc */ 30536359Smarc if (p->p_tracep != NULL) 30637728Smckusick vrele(p->p_tracep); 30738423Smarc VREF(vp); 30837728Smckusick p->p_tracep = vp; 30936359Smarc } 31036359Smarc p->p_traceflag |= facs; 31147548Skarels if (curp->p_ucred->cr_uid == 0) 31246424Smarc p->p_traceflag |= KTRFAC_ROOT; 31336359Smarc } else { 31436359Smarc /* KTROP_CLEAR */ 31546424Smarc if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { 31640805Smarc /* no more tracing */ 31740805Smarc p->p_traceflag = 0; 31836359Smarc if (p->p_tracep != NULL) { 31937728Smckusick vrele(p->p_tracep); 32036359Smarc p->p_tracep = NULL; 32136359Smarc } 32236359Smarc } 32336359Smarc } 32437593Smarc 32546424Smarc return (1); 32636359Smarc } 32737593Smarc 32846424Smarc ktrsetchildren(curp, top, ops, facs, vp) 32946424Smarc struct proc *curp, *top; 33037728Smckusick struct vnode *vp; 33136359Smarc { 33236359Smarc register struct proc *p; 33337593Smarc register int ret = 0; 33436359Smarc 33536359Smarc p = top; 33636359Smarc for (;;) { 33746424Smarc ret |= ktrops(curp, p, ops, facs, vp); 33836359Smarc /* 33936359Smarc * If this process has children, descend to them next, 34036359Smarc * otherwise do any siblings, and if done with this level, 34136359Smarc * follow back up the tree (but not past top). 34236359Smarc */ 34336359Smarc if (p->p_cptr) 34436359Smarc p = p->p_cptr; 34536359Smarc else if (p == top) 34646424Smarc return (ret); 34736359Smarc else if (p->p_osptr) 34836359Smarc p = p->p_osptr; 34936359Smarc else for (;;) { 35036359Smarc p = p->p_pptr; 35136359Smarc if (p == top) 35246424Smarc return (ret); 35336359Smarc if (p->p_osptr) { 35436359Smarc p = p->p_osptr; 35536359Smarc break; 35636359Smarc } 35736359Smarc } 35836359Smarc } 35937593Smarc /*NOTREACHED*/ 36036359Smarc } 36136359Smarc 36237728Smckusick ktrwrite(vp, kth) 36337728Smckusick struct vnode *vp; 36437728Smckusick register struct ktr_header *kth; 36536359Smarc { 36637728Smckusick struct uio auio; 36737728Smckusick struct iovec aiov[2]; 36848017Smckusick register struct proc *p = curproc; /* XXX */ 36939581Smckusick int error; 37037728Smckusick 37137728Smckusick if (vp == NULL) 37237593Smarc return; 37337728Smckusick auio.uio_iov = &aiov[0]; 37437728Smckusick auio.uio_offset = 0; 37537728Smckusick auio.uio_segflg = UIO_SYSSPACE; 37637728Smckusick auio.uio_rw = UIO_WRITE; 37737728Smckusick aiov[0].iov_base = (caddr_t)kth; 37837728Smckusick aiov[0].iov_len = sizeof(struct ktr_header); 37937728Smckusick auio.uio_resid = sizeof(struct ktr_header); 38037728Smckusick auio.uio_iovcnt = 1; 38148017Smckusick auio.uio_procp = (struct proc *)0; 38236359Smarc if (kth->ktr_len > 0) { 38337728Smckusick auio.uio_iovcnt++; 38437728Smckusick aiov[1].iov_base = kth->ktr_buf; 38537728Smckusick aiov[1].iov_len = kth->ktr_len; 38637728Smckusick auio.uio_resid += kth->ktr_len; 38736359Smarc } 38839581Smckusick VOP_LOCK(vp); 38948017Smckusick error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred); 39039581Smckusick VOP_UNLOCK(vp); 39141573Smckusick if (!error) 39241573Smckusick return; 39341573Smckusick /* 39441573Smckusick * If error encountered, give up tracing on this vnode. 39541573Smckusick */ 39647548Skarels log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", 39747548Skarels error); 39854757Storek for (p = (struct proc *)allproc; p != NULL; p = p->p_nxt) { 39941573Smckusick if (p->p_tracep == vp) { 40041573Smckusick p->p_tracep = NULL; 40141573Smckusick p->p_traceflag = 0; 40241573Smckusick vrele(vp); 40341573Smckusick } 40441573Smckusick } 40536359Smarc } 40646424Smarc 40746424Smarc /* 40846424Smarc * Return true if caller has permission to set the ktracing state 40946424Smarc * of target. Essentially, the target can't possess any 41046424Smarc * more permissions than the caller. KTRFAC_ROOT signifies that 41146424Smarc * root previously set the tracing status on the target process, and 41246424Smarc * so, only root may further change it. 41346424Smarc * 41447548Skarels * TODO: check groups. use caller effective gid. 41546424Smarc */ 41647548Skarels ktrcanset(callp, targetp) 41747548Skarels struct proc *callp, *targetp; 41846424Smarc { 41947548Skarels register struct pcred *caller = callp->p_cred; 42047548Skarels register struct pcred *target = targetp->p_cred; 42147548Skarels 42247548Skarels if ((caller->pc_ucred->cr_uid == target->p_ruid && 42346424Smarc target->p_ruid == target->p_svuid && 42446424Smarc caller->p_rgid == target->p_rgid && /* XXX */ 42546424Smarc target->p_rgid == target->p_svgid && 42647548Skarels (targetp->p_traceflag & KTRFAC_ROOT) == 0) || 42747548Skarels caller->pc_ucred->cr_uid == 0) 42846424Smarc return (1); 42946424Smarc 43046424Smarc return (0); 43146424Smarc } 43246424Smarc 43336359Smarc #endif 434