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*37728Smckusick * @(#)kern_ktrace.c 1.4 (Berkeley) 05/09/89 1836359Smarc */ 1936359Smarc 2036359Smarc #ifdef KTRACE 2136359Smarc 2236359Smarc #include "param.h" 2336359Smarc #include "user.h" 2436359Smarc #include "proc.h" 25*37728Smckusick #include "file.h" 26*37728Smckusick #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 51*37728Smckusick ktrsyscall(vp, code, narg) 52*37728Smckusick 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; 69*37728Smckusick ktrwrite(vp, kth); 7036359Smarc FREE(ktp, M_TEMP); 7136359Smarc FREE(kth, M_TEMP); 7236359Smarc } 7336359Smarc 74*37728Smckusick ktrsysret(vp, code) 75*37728Smckusick 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 92*37728Smckusick ktrwrite(vp, kth); 9336359Smarc FREE(ktp, M_TEMP); 9436359Smarc FREE(kth, M_TEMP); 9536359Smarc } 9636359Smarc 97*37728Smckusick ktrnamei(vp, path) 98*37728Smckusick 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 108*37728Smckusick ktrwrite(vp, kth); 10936359Smarc FREE(kth, M_TEMP); 11036359Smarc } 11136359Smarc 112*37728Smckusick ktrgenio(vp, fd, rw, iov, len) 113*37728Smckusick 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 141*37728Smckusick 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; 158*37728Smckusick 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; 178*37728Smckusick if (u.u_error = vn_open(ndp, FREAD|FWRITE, 0)) 17936359Smarc return; 180*37728Smckusick vp = ndp->ni_vp; 181*37728Smckusick if (vp->v_type != VREG) { 18236359Smarc u.u_error = EACCES; 183*37728Smckusick 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) { 192*37728Smckusick if (p->p_tracep == vp) { 19336359Smarc p->p_flag &= ~SKTR; 19436359Smarc p->p_tracep = NULL; 19536359Smarc p->p_traceflag = 0; 196*37728Smckusick 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) 218*37728Smckusick ret |= ktrsetchildren(p, ops, facs, vp); 21936359Smarc else 220*37728Smckusick 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) 229*37728Smckusick ret |= ktrsetchildren(p, ops, facs, vp); 23036359Smarc else 231*37728Smckusick ret |= ktrops(p, ops, facs, vp); 23236359Smarc } 23337593Smarc if (!ret) 23437593Smarc u.u_error = EPERM; 23536359Smarc done: 236*37728Smckusick if (vp != NULL) 237*37728Smckusick vrele(vp); 23836359Smarc } 23936359Smarc 240*37728Smckusick ktrops(p, ops, facs, vp) 24136359Smarc struct proc *p; 242*37728Smckusick struct vnode *vp; 24336359Smarc { 24437593Smarc 24537593Smarc if (u.u_uid && u.u_uid != p->p_uid) 24637593Smarc return 0; 24736359Smarc if (ops == KTROP_SET) { 248*37728Smckusick if (p->p_tracep != vp) { 24936359Smarc /* 25036359Smarc * if trace file already in use, relinquish 25136359Smarc */ 25236359Smarc if (p->p_tracep != NULL) 253*37728Smckusick vrele(p->p_tracep); 254*37728Smckusick if (vp->v_count == 0) 255*37728Smckusick panic("ktrace: bad vnode"); 256*37728Smckusick p->p_tracep = vp; 25736359Smarc } 25836359Smarc p->p_traceflag |= facs; 25936359Smarc } else { 26036359Smarc /* KTROP_CLEAR */ 26136359Smarc if ((p->p_traceflag &= ~facs) == 0) { 26236359Smarc if (p->p_tracep != NULL) { 263*37728Smckusick vrele(p->p_tracep); 26436359Smarc p->p_tracep = NULL; 26536359Smarc } 26637593Smarc p->p_flag &= ~SKTR; 26736359Smarc } 26836359Smarc } 26937593Smarc 27037593Smarc return 1; 27136359Smarc } 27237593Smarc 273*37728Smckusick ktrsetchildren(top, ops, facs, vp) 27436359Smarc struct proc *top; 275*37728Smckusick struct vnode *vp; 27636359Smarc { 27736359Smarc register struct proc *p; 27836359Smarc register int ndx; 27937593Smarc register int ret = 0; 28036359Smarc 28136359Smarc p = top; 28236359Smarc for (;;) { 283*37728Smckusick if ((ret |= ktrops(p, ops, facs, vp)) && ops == KTROP_SET) 28436359Smarc p->p_flag |= SKTR; 28536359Smarc /* 28636359Smarc * If this process has children, descend to them next, 28736359Smarc * otherwise do any siblings, and if done with this level, 28836359Smarc * follow back up the tree (but not past top). 28936359Smarc */ 29036359Smarc if (p->p_cptr) 29136359Smarc p = p->p_cptr; 29236359Smarc else if (p == top) 29337593Smarc return ret; 29436359Smarc else if (p->p_osptr) 29536359Smarc p = p->p_osptr; 29636359Smarc else for (;;) { 29736359Smarc p = p->p_pptr; 29836359Smarc if (p == top) 29937593Smarc return ret; 30036359Smarc if (p->p_osptr) { 30136359Smarc p = p->p_osptr; 30236359Smarc break; 30336359Smarc } 30436359Smarc } 30536359Smarc } 30637593Smarc /*NOTREACHED*/ 30736359Smarc } 30836359Smarc 309*37728Smckusick ktrwrite(vp, kth) 310*37728Smckusick struct vnode *vp; 311*37728Smckusick register struct ktr_header *kth; 31236359Smarc { 313*37728Smckusick struct uio auio; 314*37728Smckusick struct iovec aiov[2]; 315*37728Smckusick int offset, error; 316*37728Smckusick 317*37728Smckusick if (vp == NULL) 31837593Smarc return; 319*37728Smckusick auio.uio_iov = &aiov[0]; 320*37728Smckusick auio.uio_offset = 0; 321*37728Smckusick auio.uio_segflg = UIO_SYSSPACE; 322*37728Smckusick auio.uio_rw = UIO_WRITE; 323*37728Smckusick aiov[0].iov_base = (caddr_t)kth; 324*37728Smckusick aiov[0].iov_len = sizeof(struct ktr_header); 325*37728Smckusick auio.uio_resid = sizeof(struct ktr_header); 326*37728Smckusick auio.uio_iovcnt = 1; 32736359Smarc if (kth->ktr_len > 0) { 328*37728Smckusick auio.uio_iovcnt++; 329*37728Smckusick aiov[1].iov_base = kth->ktr_buf; 330*37728Smckusick aiov[1].iov_len = kth->ktr_len; 331*37728Smckusick auio.uio_resid += kth->ktr_len; 33236359Smarc } 333*37728Smckusick error = VOP_WRITE(vp, &auio, &offset, IO_UNIT|IO_APPEND, u.u_cred); 33436359Smarc } 33536359Smarc #endif 336