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*41573Smckusick * @(#)kern_ktrace.c 7.5 (Berkeley) 05/10/90 1836359Smarc */ 1936359Smarc 2036359Smarc #ifdef KTRACE 2136359Smarc 2236359Smarc #include "param.h" 2336359Smarc #include "user.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 5137728Smckusick ktrsyscall(vp, code, narg) 5237728Smckusick struct vnode *vp; 5336359Smarc { 5436359Smarc struct ktr_header *kth = ktrgetheader(KTR_SYSCALL); 5536359Smarc struct ktr_syscall *ktp; 5636359Smarc register len = sizeof(struct ktr_syscall) + (narg * sizeof(int)); 5736359Smarc int *argp, i; 5836359Smarc 5937593Smarc if (kth == NULL) 6036359Smarc return; 6136359Smarc MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); 6236359Smarc ktp->ktr_code = code; 6336359Smarc ktp->ktr_narg = narg; 6436359Smarc argp = (int *)((char *)ktp + sizeof(struct ktr_syscall)); 6536359Smarc for (i = 0; i < narg; i++) 6636359Smarc *argp++ = u.u_arg[i]; 6736359Smarc kth->ktr_buf = (caddr_t)ktp; 6836359Smarc kth->ktr_len = len; 6937728Smckusick ktrwrite(vp, kth); 7036359Smarc FREE(ktp, M_TEMP); 7136359Smarc FREE(kth, M_TEMP); 7236359Smarc } 7336359Smarc 7437728Smckusick ktrsysret(vp, code) 7537728Smckusick struct vnode *vp; 7636359Smarc { 7736359Smarc struct ktr_header *kth = ktrgetheader(KTR_SYSRET); 7840805Smarc struct ktr_sysret ktp; 7936359Smarc 8037593Smarc if (kth == NULL) 8136359Smarc return; 8240805Smarc ktp.ktr_code = code; 8340805Smarc ktp.ktr_error = u.u_error; 8440805Smarc ktp.ktr_retval = u.u_r.r_val1; /* what about val2 ? */ 8536359Smarc 8640805Smarc kth->ktr_buf = (caddr_t)&ktp; 8736359Smarc kth->ktr_len = sizeof(struct ktr_sysret); 8836359Smarc 8937728Smckusick ktrwrite(vp, kth); 9036359Smarc FREE(kth, M_TEMP); 9136359Smarc } 9236359Smarc 9337728Smckusick ktrnamei(vp, path) 9437728Smckusick struct vnode *vp; 9536359Smarc char *path; 9636359Smarc { 9736359Smarc struct ktr_header *kth = ktrgetheader(KTR_NAMEI); 9836359Smarc 9937593Smarc if (kth == NULL) 10036359Smarc return; 10136359Smarc kth->ktr_len = strlen(path); 10236359Smarc kth->ktr_buf = path; 10336359Smarc 10437728Smckusick ktrwrite(vp, kth); 10536359Smarc FREE(kth, M_TEMP); 10636359Smarc } 10736359Smarc 10837728Smckusick ktrgenio(vp, fd, rw, iov, len) 10937728Smckusick struct vnode *vp; 11037593Smarc enum uio_rw rw; 11137593Smarc register struct iovec *iov; 11237593Smarc { 11337593Smarc struct ktr_header *kth = ktrgetheader(KTR_GENIO); 11437593Smarc register struct ktr_genio *ktp; 11537593Smarc register caddr_t cp; 11637593Smarc register int resid = len, cnt; 11737593Smarc 11837593Smarc if (kth == NULL || u.u_error) 11937593Smarc return; 12037593Smarc MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, 12137593Smarc M_TEMP, M_WAITOK); 12237593Smarc ktp->ktr_fd = fd; 12337593Smarc ktp->ktr_rw = rw; 12437593Smarc cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); 12537593Smarc while (resid > 0) { 12637593Smarc if ((cnt = iov->iov_len) > resid) 12737593Smarc cnt = resid; 128*41573Smckusick if (copyin(iov->iov_base, cp, (unsigned)cnt)) 12937593Smarc goto done; 13037593Smarc cp += cnt; 13137593Smarc resid -= cnt; 13237593Smarc iov++; 13337593Smarc } 13437593Smarc kth->ktr_buf = (caddr_t)ktp; 13537593Smarc kth->ktr_len = sizeof (struct ktr_genio) + len; 13637593Smarc 13737728Smckusick ktrwrite(vp, kth); 13837593Smarc done: 13937593Smarc FREE(kth, M_TEMP); 14037593Smarc FREE(ktp, M_TEMP); 14137593Smarc } 14237593Smarc 14340805Smarc ktrpsig(vp, sig, action, mask, code) 14440805Smarc struct vnode *vp; 14540805Smarc sig_t action; 14640805Smarc { 14740805Smarc struct ktr_header *kth = ktrgetheader(KTR_PSIG); 14840805Smarc struct ktr_psig kp; 14940805Smarc 15040805Smarc if (kth == NULL) 15140805Smarc return; 15240805Smarc kp.signo = (char)sig; 15340805Smarc kp.action = action; 15440805Smarc kp.mask = mask; 15540805Smarc kp.code = code; 15640805Smarc kth->ktr_buf = (caddr_t)&kp; 15740805Smarc kth->ktr_len = sizeof (struct ktr_psig); 15840805Smarc 15940805Smarc ktrwrite(vp, kth); 16040805Smarc FREE(kth, M_TEMP); 16140805Smarc } 16240805Smarc 16340805Smarc /* Interface and common routines */ 16440805Smarc 16536359Smarc /* 16636359Smarc * ktrace system call 16736359Smarc */ 16836359Smarc ktrace() 16936359Smarc { 17036359Smarc register struct a { 17136359Smarc char *fname; 17236359Smarc int ops; 17336359Smarc int facs; 17437593Smarc int pid; 17536359Smarc } *uap = (struct a *)u.u_ap; 17637728Smckusick register struct vnode *vp = NULL; 17736359Smarc register struct nameidata *ndp = &u.u_nd; 17836359Smarc register struct proc *p; 17940805Smarc register ops = KTROP(uap->ops); 18036359Smarc struct pgrp *pg; 18136359Smarc register int facs = uap->facs; 18237593Smarc register int ret = 0; 18336359Smarc 18436359Smarc /* 18536359Smarc * Until security implications are thought through, 18637593Smarc * limit tracing to root (unless ktrace_nocheck is set). 18736359Smarc */ 18837555Smckusick if (!ktrace_nocheck && (u.u_error = suser(u.u_cred, &u.u_acflag))) 18936359Smarc return; 19036359Smarc if (ops != KTROP_CLEAR) { 19136359Smarc /* 19236359Smarc * an operation which requires a file argument. 19336359Smarc */ 19436359Smarc ndp->ni_segflg = UIO_USERSPACE; 19536359Smarc ndp->ni_dirp = uap->fname; 19637728Smckusick if (u.u_error = vn_open(ndp, FREAD|FWRITE, 0)) 19736359Smarc return; 19837728Smckusick vp = ndp->ni_vp; 19937728Smckusick if (vp->v_type != VREG) { 20036359Smarc u.u_error = EACCES; 20137728Smckusick vrele(vp); 20236359Smarc return; 20336359Smarc } 20436359Smarc } 20536359Smarc /* 20636359Smarc * Clear all uses of the tracefile 20736359Smarc */ 20836359Smarc if (ops == KTROP_CLEARFILE) { 20936359Smarc for (p = allproc; p != NULL; p = p->p_nxt) { 21037728Smckusick if (p->p_tracep == vp) { 21136359Smarc p->p_tracep = NULL; 21236359Smarc p->p_traceflag = 0; 21337728Smckusick vrele(vp); 21436359Smarc } 21536359Smarc } 21636359Smarc goto done; 21736359Smarc } 21836359Smarc /* 21936359Smarc * need something to (un)trace 22036359Smarc */ 22136359Smarc if (!facs) { 22236359Smarc u.u_error = EINVAL; 22336359Smarc goto done; 22436359Smarc } 22540805Smarc /* 22640805Smarc * doit 22740805Smarc */ 22836359Smarc if (uap->pid < 0) { 22936359Smarc pg = pgfind(-uap->pid); 23036359Smarc if (pg == NULL) { 23136359Smarc u.u_error = ESRCH; 23236359Smarc goto done; 23336359Smarc } 23436359Smarc for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) 23540805Smarc if (uap->ops&KTRFLAG_DESCEND) 23637728Smckusick ret |= ktrsetchildren(p, ops, facs, vp); 23736359Smarc else 23837728Smckusick ret |= ktrops(p, ops, facs, vp); 23936359Smarc 24036359Smarc } else { 24136359Smarc p = pfind(uap->pid); 24236359Smarc if (p == NULL) { 24336359Smarc u.u_error = ESRCH; 24436359Smarc goto done; 24536359Smarc } 24640805Smarc if (ops&KTRFLAG_DESCEND) 24737728Smckusick ret |= ktrsetchildren(p, ops, facs, vp); 24836359Smarc else 24937728Smckusick ret |= ktrops(p, ops, facs, vp); 25036359Smarc } 25137593Smarc if (!ret) 25237593Smarc u.u_error = EPERM; 25336359Smarc done: 25437728Smckusick if (vp != NULL) 25537728Smckusick vrele(vp); 25636359Smarc } 25736359Smarc 25837728Smckusick ktrops(p, ops, facs, vp) 25936359Smarc struct proc *p; 26037728Smckusick struct vnode *vp; 26136359Smarc { 26237593Smarc 26337593Smarc if (u.u_uid && u.u_uid != p->p_uid) 26437593Smarc return 0; 26536359Smarc if (ops == KTROP_SET) { 26640805Smarc if (p->p_tracep != vp) { 26736359Smarc /* 26836359Smarc * if trace file already in use, relinquish 26936359Smarc */ 27036359Smarc if (p->p_tracep != NULL) 27137728Smckusick vrele(p->p_tracep); 27238423Smarc VREF(vp); 27337728Smckusick p->p_tracep = vp; 27436359Smarc } 27536359Smarc p->p_traceflag |= facs; 27636359Smarc } else { 27736359Smarc /* KTROP_CLEAR */ 27840805Smarc if (((p->p_traceflag &= ~facs) & ~KTRFAC_INHERIT) == 0) { 27940805Smarc /* no more tracing */ 28040805Smarc p->p_traceflag = 0; 28136359Smarc if (p->p_tracep != NULL) { 28237728Smckusick vrele(p->p_tracep); 28336359Smarc p->p_tracep = NULL; 28436359Smarc } 28536359Smarc } 28636359Smarc } 28737593Smarc 28837593Smarc return 1; 28936359Smarc } 29037593Smarc 29137728Smckusick ktrsetchildren(top, ops, facs, vp) 29236359Smarc struct proc *top; 29337728Smckusick struct vnode *vp; 29436359Smarc { 29536359Smarc register struct proc *p; 29637593Smarc register int ret = 0; 29736359Smarc 29836359Smarc p = top; 29936359Smarc for (;;) { 30040805Smarc ret |= ktrops(p, ops, facs, vp); 30136359Smarc /* 30236359Smarc * If this process has children, descend to them next, 30336359Smarc * otherwise do any siblings, and if done with this level, 30436359Smarc * follow back up the tree (but not past top). 30536359Smarc */ 30636359Smarc if (p->p_cptr) 30736359Smarc p = p->p_cptr; 30836359Smarc else if (p == top) 30937593Smarc return ret; 31036359Smarc else if (p->p_osptr) 31136359Smarc p = p->p_osptr; 31236359Smarc else for (;;) { 31336359Smarc p = p->p_pptr; 31436359Smarc if (p == top) 31537593Smarc return ret; 31636359Smarc if (p->p_osptr) { 31736359Smarc p = p->p_osptr; 31836359Smarc break; 31936359Smarc } 32036359Smarc } 32136359Smarc } 32237593Smarc /*NOTREACHED*/ 32336359Smarc } 32436359Smarc 32537728Smckusick ktrwrite(vp, kth) 32637728Smckusick struct vnode *vp; 32737728Smckusick register struct ktr_header *kth; 32836359Smarc { 32937728Smckusick struct uio auio; 33037728Smckusick struct iovec aiov[2]; 331*41573Smckusick struct proc *p; 33239581Smckusick int error; 33337728Smckusick 33437728Smckusick if (vp == NULL) 33537593Smarc return; 33637728Smckusick auio.uio_iov = &aiov[0]; 33737728Smckusick auio.uio_offset = 0; 33837728Smckusick auio.uio_segflg = UIO_SYSSPACE; 33937728Smckusick auio.uio_rw = UIO_WRITE; 34037728Smckusick aiov[0].iov_base = (caddr_t)kth; 34137728Smckusick aiov[0].iov_len = sizeof(struct ktr_header); 34237728Smckusick auio.uio_resid = sizeof(struct ktr_header); 34337728Smckusick auio.uio_iovcnt = 1; 34436359Smarc if (kth->ktr_len > 0) { 34537728Smckusick auio.uio_iovcnt++; 34637728Smckusick aiov[1].iov_base = kth->ktr_buf; 34737728Smckusick aiov[1].iov_len = kth->ktr_len; 34837728Smckusick auio.uio_resid += kth->ktr_len; 34936359Smarc } 35039581Smckusick VOP_LOCK(vp); 35139581Smckusick error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, u.u_cred); 35239581Smckusick VOP_UNLOCK(vp); 353*41573Smckusick if (!error) 354*41573Smckusick return; 355*41573Smckusick /* 356*41573Smckusick * If error encountered, give up tracing on this vnode. 357*41573Smckusick */ 358*41573Smckusick uprintf("\ntrace write failed with errno %d, tracing stopped\n", error); 359*41573Smckusick for (p = allproc; p != NULL; p = p->p_nxt) { 360*41573Smckusick if (p->p_tracep == vp) { 361*41573Smckusick p->p_tracep = NULL; 362*41573Smckusick p->p_traceflag = 0; 363*41573Smckusick vrele(vp); 364*41573Smckusick } 365*41573Smckusick } 36636359Smarc } 36736359Smarc #endif 368