136359Smarc /* 236359Smarc * Copyright (c) 1989 The Regents of the University of California. 336359Smarc * All rights reserved. 436359Smarc * 536359Smarc * Redistribution and use in source and binary forms are permitted 636359Smarc * provided that the above copyright notice and this paragraph are 736359Smarc * duplicated in all such forms and that any documentation, 836359Smarc * advertising materials, and other materials related to such 936359Smarc * distribution and use acknowledge that the software was developed 1036359Smarc * by the University of California, Berkeley. The name of the 1136359Smarc * University may not be used to endorse or promote products derived 1236359Smarc * from this software without specific prior written permission. 1336359Smarc * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1436359Smarc * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1536359Smarc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1636359Smarc * 17*43444Smckusick * @(#)kern_ktrace.c 7.6 (Berkeley) 06/22/90 1836359Smarc */ 1936359Smarc 2036359Smarc #ifdef KTRACE 2136359Smarc 2236359Smarc #include "param.h" 23*43444Smckusick #include "syscontext.h" 2436359Smarc #include "proc.h" 2537728Smckusick #include "file.h" 2637728Smckusick #include "vnode.h" 2736359Smarc #include "ktrace.h" 2836359Smarc #include "malloc.h" 2936359Smarc 3037593Smarc #include "syscalls.c" 3136359Smarc 3236359Smarc extern int nsysent; 3336359Smarc extern char *syscallnames[]; 3436359Smarc 3537593Smarc int ktrace_nocheck = 1; 3637593Smarc 3736359Smarc struct ktr_header * 3836359Smarc ktrgetheader(type) 3936359Smarc { 4036359Smarc register struct ktr_header *kth; 4136359Smarc 4236359Smarc MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 4336359Smarc M_TEMP, M_WAITOK); 4436359Smarc kth->ktr_type = type; 4537593Smarc microtime(&kth->ktr_time); 4636359Smarc kth->ktr_pid = u.u_procp->p_pid; 4740805Smarc bcopy(u.u_procp->p_comm, kth->ktr_comm, MAXCOMLEN); 4836359Smarc return (kth); 4936359Smarc } 5036359Smarc 51*43444Smckusick ktrsyscall(vp, code, narg, args) 5237728Smckusick struct vnode *vp; 53*43444Smckusick int code, narg, args[]; 5436359Smarc { 5536359Smarc struct ktr_header *kth = ktrgetheader(KTR_SYSCALL); 5636359Smarc struct ktr_syscall *ktp; 5736359Smarc register len = sizeof(struct ktr_syscall) + (narg * sizeof(int)); 5836359Smarc int *argp, i; 5936359Smarc 6037593Smarc if (kth == NULL) 6136359Smarc return; 6236359Smarc MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); 6336359Smarc ktp->ktr_code = code; 6436359Smarc ktp->ktr_narg = narg; 6536359Smarc argp = (int *)((char *)ktp + sizeof(struct ktr_syscall)); 6636359Smarc for (i = 0; i < narg; i++) 67*43444Smckusick *argp++ = args[i]; 6836359Smarc kth->ktr_buf = (caddr_t)ktp; 6936359Smarc kth->ktr_len = len; 7037728Smckusick ktrwrite(vp, kth); 7136359Smarc FREE(ktp, M_TEMP); 7236359Smarc FREE(kth, M_TEMP); 7336359Smarc } 7436359Smarc 75*43444Smckusick ktrsysret(vp, code, error, retval) 7637728Smckusick struct vnode *vp; 77*43444Smckusick int code, error, retval; 7836359Smarc { 7936359Smarc struct ktr_header *kth = ktrgetheader(KTR_SYSRET); 8040805Smarc struct ktr_sysret ktp; 8136359Smarc 8237593Smarc if (kth == NULL) 8336359Smarc return; 8440805Smarc ktp.ktr_code = code; 85*43444Smckusick ktp.ktr_error = error; 86*43444Smckusick ktp.ktr_retval = retval; /* what about val2 ? */ 8736359Smarc 8840805Smarc kth->ktr_buf = (caddr_t)&ktp; 8936359Smarc kth->ktr_len = sizeof(struct ktr_sysret); 9036359Smarc 9137728Smckusick ktrwrite(vp, kth); 9236359Smarc FREE(kth, M_TEMP); 9336359Smarc } 9436359Smarc 9537728Smckusick ktrnamei(vp, path) 9637728Smckusick struct vnode *vp; 9736359Smarc char *path; 9836359Smarc { 9936359Smarc struct ktr_header *kth = ktrgetheader(KTR_NAMEI); 10036359Smarc 10137593Smarc if (kth == NULL) 10236359Smarc return; 10336359Smarc kth->ktr_len = strlen(path); 10436359Smarc kth->ktr_buf = path; 10536359Smarc 10637728Smckusick ktrwrite(vp, kth); 10736359Smarc FREE(kth, M_TEMP); 10836359Smarc } 10936359Smarc 110*43444Smckusick ktrgenio(vp, fd, rw, iov, len, error) 11137728Smckusick struct vnode *vp; 112*43444Smckusick int fd; 11337593Smarc enum uio_rw rw; 11437593Smarc register struct iovec *iov; 11537593Smarc { 11637593Smarc struct ktr_header *kth = ktrgetheader(KTR_GENIO); 11737593Smarc register struct ktr_genio *ktp; 11837593Smarc register caddr_t cp; 11937593Smarc register int resid = len, cnt; 12037593Smarc 121*43444Smckusick if (kth == NULL || error) 12237593Smarc return; 12337593Smarc MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, 12437593Smarc M_TEMP, M_WAITOK); 12537593Smarc ktp->ktr_fd = fd; 12637593Smarc ktp->ktr_rw = rw; 12737593Smarc cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); 12837593Smarc while (resid > 0) { 12937593Smarc if ((cnt = iov->iov_len) > resid) 13037593Smarc cnt = resid; 13141573Smckusick if (copyin(iov->iov_base, cp, (unsigned)cnt)) 13237593Smarc goto done; 13337593Smarc cp += cnt; 13437593Smarc resid -= cnt; 13537593Smarc iov++; 13637593Smarc } 13737593Smarc kth->ktr_buf = (caddr_t)ktp; 13837593Smarc kth->ktr_len = sizeof (struct ktr_genio) + len; 13937593Smarc 14037728Smckusick ktrwrite(vp, kth); 14137593Smarc done: 14237593Smarc FREE(kth, M_TEMP); 14337593Smarc FREE(ktp, M_TEMP); 14437593Smarc } 14537593Smarc 14640805Smarc ktrpsig(vp, sig, action, mask, code) 14740805Smarc struct vnode *vp; 14840805Smarc sig_t action; 14940805Smarc { 15040805Smarc struct ktr_header *kth = ktrgetheader(KTR_PSIG); 15140805Smarc struct ktr_psig kp; 15240805Smarc 15340805Smarc if (kth == NULL) 15440805Smarc return; 15540805Smarc kp.signo = (char)sig; 15640805Smarc kp.action = action; 15740805Smarc kp.mask = mask; 15840805Smarc kp.code = code; 15940805Smarc kth->ktr_buf = (caddr_t)&kp; 16040805Smarc kth->ktr_len = sizeof (struct ktr_psig); 16140805Smarc 16240805Smarc ktrwrite(vp, kth); 16340805Smarc FREE(kth, M_TEMP); 16440805Smarc } 16540805Smarc 16640805Smarc /* Interface and common routines */ 16740805Smarc 16836359Smarc /* 16936359Smarc * ktrace system call 17036359Smarc */ 171*43444Smckusick /* ARGSUSED */ 172*43444Smckusick ktrace(curp, uap, retval) 173*43444Smckusick struct proc *curp; 174*43444Smckusick register struct args { 17536359Smarc char *fname; 17636359Smarc int ops; 17736359Smarc int facs; 17837593Smarc int pid; 179*43444Smckusick } *uap; 180*43444Smckusick int *retval; 181*43444Smckusick { 18237728Smckusick register struct vnode *vp = NULL; 18336359Smarc register struct nameidata *ndp = &u.u_nd; 18436359Smarc register struct proc *p; 18540805Smarc register ops = KTROP(uap->ops); 18636359Smarc struct pgrp *pg; 18736359Smarc register int facs = uap->facs; 18837593Smarc register int ret = 0; 189*43444Smckusick int error = 0; 19036359Smarc 19136359Smarc /* 19236359Smarc * Until security implications are thought through, 19337593Smarc * limit tracing to root (unless ktrace_nocheck is set). 19436359Smarc */ 195*43444Smckusick if (!ktrace_nocheck && (error = suser(u.u_cred, &u.u_acflag))) 196*43444Smckusick RETURN (error); 19736359Smarc if (ops != KTROP_CLEAR) { 19836359Smarc /* 19936359Smarc * an operation which requires a file argument. 20036359Smarc */ 20136359Smarc ndp->ni_segflg = UIO_USERSPACE; 20236359Smarc ndp->ni_dirp = uap->fname; 203*43444Smckusick if (error = vn_open(ndp, FREAD|FWRITE, 0)) 204*43444Smckusick RETURN (error); 20537728Smckusick vp = ndp->ni_vp; 20637728Smckusick if (vp->v_type != VREG) { 20737728Smckusick vrele(vp); 208*43444Smckusick RETURN (EACCES); 20936359Smarc } 21036359Smarc } 21136359Smarc /* 21236359Smarc * Clear all uses of the tracefile 21336359Smarc */ 21436359Smarc if (ops == KTROP_CLEARFILE) { 21536359Smarc for (p = allproc; p != NULL; p = p->p_nxt) { 21637728Smckusick if (p->p_tracep == vp) { 21736359Smarc p->p_tracep = NULL; 21836359Smarc p->p_traceflag = 0; 21937728Smckusick vrele(vp); 22036359Smarc } 22136359Smarc } 22236359Smarc goto done; 22336359Smarc } 22436359Smarc /* 22536359Smarc * need something to (un)trace 22636359Smarc */ 22736359Smarc if (!facs) { 228*43444Smckusick error = EINVAL; 22936359Smarc goto done; 23036359Smarc } 23140805Smarc /* 23240805Smarc * doit 23340805Smarc */ 23436359Smarc if (uap->pid < 0) { 23536359Smarc pg = pgfind(-uap->pid); 23636359Smarc if (pg == NULL) { 237*43444Smckusick error = ESRCH; 23836359Smarc goto done; 23936359Smarc } 24036359Smarc for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) 24140805Smarc if (uap->ops&KTRFLAG_DESCEND) 24237728Smckusick ret |= ktrsetchildren(p, ops, facs, vp); 24336359Smarc else 24437728Smckusick ret |= ktrops(p, ops, facs, vp); 24536359Smarc 24636359Smarc } else { 24736359Smarc p = pfind(uap->pid); 24836359Smarc if (p == NULL) { 249*43444Smckusick error = ESRCH; 25036359Smarc goto done; 25136359Smarc } 25240805Smarc if (ops&KTRFLAG_DESCEND) 25337728Smckusick ret |= ktrsetchildren(p, ops, facs, vp); 25436359Smarc else 25537728Smckusick ret |= ktrops(p, ops, facs, vp); 25636359Smarc } 25737593Smarc if (!ret) 258*43444Smckusick error = EPERM; 25936359Smarc done: 26037728Smckusick if (vp != NULL) 26137728Smckusick vrele(vp); 262*43444Smckusick RETURN (error); 26336359Smarc } 26436359Smarc 26537728Smckusick ktrops(p, ops, facs, vp) 26636359Smarc struct proc *p; 26737728Smckusick struct vnode *vp; 26836359Smarc { 26937593Smarc 27037593Smarc if (u.u_uid && u.u_uid != p->p_uid) 27137593Smarc return 0; 27236359Smarc if (ops == KTROP_SET) { 27340805Smarc if (p->p_tracep != vp) { 27436359Smarc /* 27536359Smarc * if trace file already in use, relinquish 27636359Smarc */ 27736359Smarc if (p->p_tracep != NULL) 27837728Smckusick vrele(p->p_tracep); 27938423Smarc VREF(vp); 28037728Smckusick p->p_tracep = vp; 28136359Smarc } 28236359Smarc p->p_traceflag |= facs; 28336359Smarc } else { 28436359Smarc /* KTROP_CLEAR */ 28540805Smarc if (((p->p_traceflag &= ~facs) & ~KTRFAC_INHERIT) == 0) { 28640805Smarc /* no more tracing */ 28740805Smarc p->p_traceflag = 0; 28836359Smarc if (p->p_tracep != NULL) { 28937728Smckusick vrele(p->p_tracep); 29036359Smarc p->p_tracep = NULL; 29136359Smarc } 29236359Smarc } 29336359Smarc } 29437593Smarc 29537593Smarc return 1; 29636359Smarc } 29737593Smarc 29837728Smckusick ktrsetchildren(top, ops, facs, vp) 29936359Smarc struct proc *top; 30037728Smckusick struct vnode *vp; 30136359Smarc { 30236359Smarc register struct proc *p; 30337593Smarc register int ret = 0; 30436359Smarc 30536359Smarc p = top; 30636359Smarc for (;;) { 30740805Smarc ret |= ktrops(p, ops, facs, vp); 30836359Smarc /* 30936359Smarc * If this process has children, descend to them next, 31036359Smarc * otherwise do any siblings, and if done with this level, 31136359Smarc * follow back up the tree (but not past top). 31236359Smarc */ 31336359Smarc if (p->p_cptr) 31436359Smarc p = p->p_cptr; 31536359Smarc else if (p == top) 31637593Smarc return ret; 31736359Smarc else if (p->p_osptr) 31836359Smarc p = p->p_osptr; 31936359Smarc else for (;;) { 32036359Smarc p = p->p_pptr; 32136359Smarc if (p == top) 32237593Smarc return ret; 32336359Smarc if (p->p_osptr) { 32436359Smarc p = p->p_osptr; 32536359Smarc break; 32636359Smarc } 32736359Smarc } 32836359Smarc } 32937593Smarc /*NOTREACHED*/ 33036359Smarc } 33136359Smarc 33237728Smckusick ktrwrite(vp, kth) 33337728Smckusick struct vnode *vp; 33437728Smckusick register struct ktr_header *kth; 33536359Smarc { 33637728Smckusick struct uio auio; 33737728Smckusick struct iovec aiov[2]; 33841573Smckusick struct proc *p; 33939581Smckusick int error; 34037728Smckusick 34137728Smckusick if (vp == NULL) 34237593Smarc return; 34337728Smckusick auio.uio_iov = &aiov[0]; 34437728Smckusick auio.uio_offset = 0; 34537728Smckusick auio.uio_segflg = UIO_SYSSPACE; 34637728Smckusick auio.uio_rw = UIO_WRITE; 34737728Smckusick aiov[0].iov_base = (caddr_t)kth; 34837728Smckusick aiov[0].iov_len = sizeof(struct ktr_header); 34937728Smckusick auio.uio_resid = sizeof(struct ktr_header); 35037728Smckusick auio.uio_iovcnt = 1; 35136359Smarc if (kth->ktr_len > 0) { 35237728Smckusick auio.uio_iovcnt++; 35337728Smckusick aiov[1].iov_base = kth->ktr_buf; 35437728Smckusick aiov[1].iov_len = kth->ktr_len; 35537728Smckusick auio.uio_resid += kth->ktr_len; 35636359Smarc } 35739581Smckusick VOP_LOCK(vp); 35839581Smckusick error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, u.u_cred); 35939581Smckusick VOP_UNLOCK(vp); 36041573Smckusick if (!error) 36141573Smckusick return; 36241573Smckusick /* 36341573Smckusick * If error encountered, give up tracing on this vnode. 36441573Smckusick */ 36541573Smckusick uprintf("\ntrace write failed with errno %d, tracing stopped\n", error); 36641573Smckusick for (p = allproc; p != NULL; p = p->p_nxt) { 36741573Smckusick if (p->p_tracep == vp) { 36841573Smckusick p->p_tracep = NULL; 36941573Smckusick p->p_traceflag = 0; 37041573Smckusick vrele(vp); 37141573Smckusick } 37241573Smckusick } 37336359Smarc } 37436359Smarc #endif 375