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*38423Smarc * @(#)kern_ktrace.c 1.5 (Berkeley) 07/05/89 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; 4736359Smarc bcopy(u.u_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); 7836359Smarc struct ktr_sysret *ktp; 7936359Smarc 8037593Smarc if (kth == NULL) 8136359Smarc return; 8236359Smarc MALLOC(ktp, struct ktr_sysret *, sizeof(struct ktr_sysret), 8336359Smarc M_TEMP , M_WAITOK); 8436359Smarc ktp->ktr_code = code; 8536359Smarc ktp->ktr_eosys = u.u_eosys; 8636359Smarc ktp->ktr_error = u.u_error; 8736359Smarc ktp->ktr_retval = u.u_r.r_val1; /* what about val2 ? */ 8836359Smarc 8936359Smarc kth->ktr_buf = (caddr_t)ktp; 9036359Smarc kth->ktr_len = sizeof(struct ktr_sysret); 9136359Smarc 9237728Smckusick ktrwrite(vp, kth); 9336359Smarc FREE(ktp, M_TEMP); 9436359Smarc FREE(kth, M_TEMP); 9536359Smarc } 9636359Smarc 9737728Smckusick ktrnamei(vp, path) 9837728Smckusick struct vnode *vp; 9936359Smarc char *path; 10036359Smarc { 10136359Smarc struct ktr_header *kth = ktrgetheader(KTR_NAMEI); 10236359Smarc 10337593Smarc if (kth == NULL) 10436359Smarc return; 10536359Smarc kth->ktr_len = strlen(path); 10636359Smarc kth->ktr_buf = path; 10736359Smarc 10837728Smckusick ktrwrite(vp, kth); 10936359Smarc FREE(kth, M_TEMP); 11036359Smarc } 11136359Smarc 11237728Smckusick ktrgenio(vp, fd, rw, iov, len) 11337728Smckusick struct vnode *vp; 11437593Smarc enum uio_rw rw; 11537593Smarc register struct iovec *iov; 11637593Smarc { 11737593Smarc struct ktr_header *kth = ktrgetheader(KTR_GENIO); 11837593Smarc register struct ktr_genio *ktp; 11937593Smarc register caddr_t cp; 12037593Smarc register int resid = len, cnt; 12137593Smarc 12237593Smarc if (kth == NULL || u.u_error) 12337593Smarc return; 12437593Smarc MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, 12537593Smarc M_TEMP, M_WAITOK); 12637593Smarc ktp->ktr_fd = fd; 12737593Smarc ktp->ktr_rw = rw; 12837593Smarc cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); 12937593Smarc while (resid > 0) { 13037593Smarc if ((cnt = iov->iov_len) > resid) 13137593Smarc cnt = resid; 13237593Smarc if (copyin(iov->iov_base, cp, cnt)) 13337593Smarc goto done; 13437593Smarc cp += cnt; 13537593Smarc resid -= cnt; 13637593Smarc iov++; 13737593Smarc } 13837593Smarc kth->ktr_buf = (caddr_t)ktp; 13937593Smarc kth->ktr_len = sizeof (struct ktr_genio) + len; 14037593Smarc 14137728Smckusick ktrwrite(vp, kth); 14237593Smarc done: 14337593Smarc FREE(kth, M_TEMP); 14437593Smarc FREE(ktp, M_TEMP); 14537593Smarc } 14637593Smarc 14736359Smarc /* 14836359Smarc * ktrace system call 14936359Smarc */ 15036359Smarc ktrace() 15136359Smarc { 15236359Smarc register struct a { 15336359Smarc char *fname; 15436359Smarc int ops; 15536359Smarc int facs; 15637593Smarc int pid; 15736359Smarc } *uap = (struct a *)u.u_ap; 15837728Smckusick register struct vnode *vp = NULL; 15936359Smarc register struct nameidata *ndp = &u.u_nd; 16036359Smarc register struct proc *p; 16136359Smarc struct pgrp *pg; 16236359Smarc register int ops = uap->ops&0x3; 16336359Smarc register int facs = uap->facs; 16437593Smarc register int ret = 0; 16536359Smarc 16636359Smarc /* 16736359Smarc * Until security implications are thought through, 16837593Smarc * limit tracing to root (unless ktrace_nocheck is set). 16936359Smarc */ 17037555Smckusick if (!ktrace_nocheck && (u.u_error = suser(u.u_cred, &u.u_acflag))) 17136359Smarc return; 17236359Smarc if (ops != KTROP_CLEAR) { 17336359Smarc /* 17436359Smarc * an operation which requires a file argument. 17536359Smarc */ 17636359Smarc ndp->ni_segflg = UIO_USERSPACE; 17736359Smarc ndp->ni_dirp = uap->fname; 17837728Smckusick if (u.u_error = vn_open(ndp, FREAD|FWRITE, 0)) 17936359Smarc return; 18037728Smckusick vp = ndp->ni_vp; 18137728Smckusick if (vp->v_type != VREG) { 18236359Smarc u.u_error = EACCES; 18337728Smckusick vrele(vp); 18436359Smarc return; 18536359Smarc } 18636359Smarc } 18736359Smarc /* 18836359Smarc * Clear all uses of the tracefile 18936359Smarc */ 19036359Smarc if (ops == KTROP_CLEARFILE) { 19136359Smarc for (p = allproc; p != NULL; p = p->p_nxt) { 19237728Smckusick if (p->p_tracep == vp) { 19336359Smarc p->p_flag &= ~SKTR; 19436359Smarc p->p_tracep = NULL; 19536359Smarc p->p_traceflag = 0; 19637728Smckusick vrele(vp); 19736359Smarc } 19836359Smarc } 19936359Smarc goto done; 20036359Smarc } 20136359Smarc 20236359Smarc /* 20336359Smarc * need something to (un)trace 20436359Smarc */ 20536359Smarc if (!facs) { 20636359Smarc u.u_error = EINVAL; 20736359Smarc goto done; 20836359Smarc } 20936359Smarc 21036359Smarc if (uap->pid < 0) { 21136359Smarc pg = pgfind(-uap->pid); 21236359Smarc if (pg == NULL) { 21336359Smarc u.u_error = ESRCH; 21436359Smarc goto done; 21536359Smarc } 21636359Smarc for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) 21736359Smarc if (uap->ops&KTROP_INHERITFLAG) 21837728Smckusick ret |= ktrsetchildren(p, ops, facs, vp); 21936359Smarc else 22037728Smckusick ret |= ktrops(p, ops, facs, vp); 22136359Smarc 22236359Smarc } else { 22336359Smarc p = pfind(uap->pid); 22436359Smarc if (p == NULL) { 22536359Smarc u.u_error = ESRCH; 22636359Smarc goto done; 22736359Smarc } 22836359Smarc if (uap->ops&KTROP_INHERITFLAG) 22937728Smckusick ret |= ktrsetchildren(p, ops, facs, vp); 23036359Smarc else 23137728Smckusick ret |= ktrops(p, ops, facs, vp); 23236359Smarc } 23337593Smarc if (!ret) 23437593Smarc u.u_error = EPERM; 23536359Smarc done: 23637728Smckusick if (vp != NULL) 23737728Smckusick vrele(vp); 23836359Smarc } 23936359Smarc 24037728Smckusick ktrops(p, ops, facs, vp) 24136359Smarc struct proc *p; 24237728Smckusick struct vnode *vp; 24336359Smarc { 24437593Smarc 24537593Smarc if (u.u_uid && u.u_uid != p->p_uid) 24637593Smarc return 0; 24736359Smarc if (ops == KTROP_SET) { 24837728Smckusick if (p->p_tracep != vp) { 24936359Smarc /* 25036359Smarc * if trace file already in use, relinquish 25136359Smarc */ 25236359Smarc if (p->p_tracep != NULL) 25337728Smckusick vrele(p->p_tracep); 254*38423Smarc VREF(vp); 25537728Smckusick p->p_tracep = vp; 25636359Smarc } 25736359Smarc p->p_traceflag |= facs; 25836359Smarc } else { 25936359Smarc /* KTROP_CLEAR */ 26036359Smarc if ((p->p_traceflag &= ~facs) == 0) { 26136359Smarc if (p->p_tracep != NULL) { 26237728Smckusick vrele(p->p_tracep); 26336359Smarc p->p_tracep = NULL; 26436359Smarc } 26537593Smarc p->p_flag &= ~SKTR; 26636359Smarc } 26736359Smarc } 26837593Smarc 26937593Smarc return 1; 27036359Smarc } 27137593Smarc 27237728Smckusick ktrsetchildren(top, ops, facs, vp) 27336359Smarc struct proc *top; 27437728Smckusick struct vnode *vp; 27536359Smarc { 27636359Smarc register struct proc *p; 27736359Smarc register int ndx; 27837593Smarc register int ret = 0; 27936359Smarc 28036359Smarc p = top; 28136359Smarc for (;;) { 28237728Smckusick if ((ret |= ktrops(p, ops, facs, vp)) && ops == KTROP_SET) 28336359Smarc p->p_flag |= SKTR; 28436359Smarc /* 28536359Smarc * If this process has children, descend to them next, 28636359Smarc * otherwise do any siblings, and if done with this level, 28736359Smarc * follow back up the tree (but not past top). 28836359Smarc */ 28936359Smarc if (p->p_cptr) 29036359Smarc p = p->p_cptr; 29136359Smarc else if (p == top) 29237593Smarc return ret; 29336359Smarc else if (p->p_osptr) 29436359Smarc p = p->p_osptr; 29536359Smarc else for (;;) { 29636359Smarc p = p->p_pptr; 29736359Smarc if (p == top) 29837593Smarc return ret; 29936359Smarc if (p->p_osptr) { 30036359Smarc p = p->p_osptr; 30136359Smarc break; 30236359Smarc } 30336359Smarc } 30436359Smarc } 30537593Smarc /*NOTREACHED*/ 30636359Smarc } 30736359Smarc 30837728Smckusick ktrwrite(vp, kth) 30937728Smckusick struct vnode *vp; 31037728Smckusick register struct ktr_header *kth; 31136359Smarc { 31237728Smckusick struct uio auio; 31337728Smckusick struct iovec aiov[2]; 31437728Smckusick int offset, error; 31537728Smckusick 31637728Smckusick if (vp == NULL) 31737593Smarc return; 31837728Smckusick auio.uio_iov = &aiov[0]; 31937728Smckusick auio.uio_offset = 0; 32037728Smckusick auio.uio_segflg = UIO_SYSSPACE; 32137728Smckusick auio.uio_rw = UIO_WRITE; 32237728Smckusick aiov[0].iov_base = (caddr_t)kth; 32337728Smckusick aiov[0].iov_len = sizeof(struct ktr_header); 32437728Smckusick auio.uio_resid = sizeof(struct ktr_header); 32537728Smckusick auio.uio_iovcnt = 1; 32636359Smarc if (kth->ktr_len > 0) { 32737728Smckusick auio.uio_iovcnt++; 32837728Smckusick aiov[1].iov_base = kth->ktr_buf; 32937728Smckusick aiov[1].iov_len = kth->ktr_len; 33037728Smckusick auio.uio_resid += kth->ktr_len; 33136359Smarc } 33237728Smckusick error = VOP_WRITE(vp, &auio, &offset, IO_UNIT|IO_APPEND, u.u_cred); 33336359Smarc } 33436359Smarc #endif 335