kern_ktrace.c revision 8876
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 3. All advertising materials mentioning features or use of this software 141541Srgrimes * must display the following acknowledgement: 151541Srgrimes * This product includes software developed by the University of 161541Srgrimes * California, Berkeley and its contributors. 171541Srgrimes * 4. Neither the name of the University nor the names of its contributors 181541Srgrimes * may be used to endorse or promote products derived from this software 191541Srgrimes * without specific prior written permission. 201541Srgrimes * 211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311541Srgrimes * SUCH DAMAGE. 321541Srgrimes * 331541Srgrimes * @(#)kern_ktrace.c 8.2 (Berkeley) 9/23/93 348876Srgrimes * $Id: kern_ktrace.c,v 1.5 1994/10/02 17:35:15 phk Exp $ 351541Srgrimes */ 361541Srgrimes 371541Srgrimes#ifdef KTRACE 381541Srgrimes 391541Srgrimes#include <sys/param.h> 402112Swollman#include <sys/systm.h> 411541Srgrimes#include <sys/proc.h> 421541Srgrimes#include <sys/file.h> 431541Srgrimes#include <sys/namei.h> 441541Srgrimes#include <sys/vnode.h> 451541Srgrimes#include <sys/ktrace.h> 461541Srgrimes#include <sys/malloc.h> 471541Srgrimes#include <sys/syslog.h> 481541Srgrimes 491541Srgrimesstruct ktr_header * 501541Srgrimesktrgetheader(type) 511541Srgrimes int type; 521541Srgrimes{ 531541Srgrimes register struct ktr_header *kth; 541541Srgrimes struct proc *p = curproc; /* XXX */ 551541Srgrimes 568876Srgrimes MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 571541Srgrimes M_TEMP, M_WAITOK); 581541Srgrimes kth->ktr_type = type; 591541Srgrimes microtime(&kth->ktr_time); 601541Srgrimes kth->ktr_pid = p->p_pid; 611541Srgrimes bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN); 621541Srgrimes return (kth); 631541Srgrimes} 641541Srgrimes 651549Srgrimesvoid 661541Srgrimesktrsyscall(vp, code, narg, args) 671541Srgrimes struct vnode *vp; 681541Srgrimes int code, narg, args[]; 691541Srgrimes{ 701541Srgrimes struct ktr_header *kth; 711541Srgrimes struct ktr_syscall *ktp; 721541Srgrimes register len = sizeof(struct ktr_syscall) + (narg * sizeof(int)); 731541Srgrimes struct proc *p = curproc; /* XXX */ 741541Srgrimes int *argp, i; 751541Srgrimes 761541Srgrimes p->p_traceflag |= KTRFAC_ACTIVE; 771541Srgrimes kth = ktrgetheader(KTR_SYSCALL); 781541Srgrimes MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); 791541Srgrimes ktp->ktr_code = code; 801541Srgrimes ktp->ktr_narg = narg; 811541Srgrimes argp = (int *)((char *)ktp + sizeof(struct ktr_syscall)); 821541Srgrimes for (i = 0; i < narg; i++) 831541Srgrimes *argp++ = args[i]; 841541Srgrimes kth->ktr_buf = (caddr_t)ktp; 851541Srgrimes kth->ktr_len = len; 861541Srgrimes ktrwrite(vp, kth); 871541Srgrimes FREE(ktp, M_TEMP); 881541Srgrimes FREE(kth, M_TEMP); 891541Srgrimes p->p_traceflag &= ~KTRFAC_ACTIVE; 901541Srgrimes} 911541Srgrimes 921549Srgrimesvoid 931541Srgrimesktrsysret(vp, code, error, retval) 941541Srgrimes struct vnode *vp; 951541Srgrimes int code, error, retval; 961541Srgrimes{ 971541Srgrimes struct ktr_header *kth; 981541Srgrimes struct ktr_sysret ktp; 991541Srgrimes struct proc *p = curproc; /* XXX */ 1001541Srgrimes 1011541Srgrimes p->p_traceflag |= KTRFAC_ACTIVE; 1021541Srgrimes kth = ktrgetheader(KTR_SYSRET); 1031541Srgrimes ktp.ktr_code = code; 1041541Srgrimes ktp.ktr_error = error; 1051541Srgrimes ktp.ktr_retval = retval; /* what about val2 ? */ 1061541Srgrimes 1071541Srgrimes kth->ktr_buf = (caddr_t)&ktp; 1081541Srgrimes kth->ktr_len = sizeof(struct ktr_sysret); 1091541Srgrimes 1101541Srgrimes ktrwrite(vp, kth); 1111541Srgrimes FREE(kth, M_TEMP); 1121541Srgrimes p->p_traceflag &= ~KTRFAC_ACTIVE; 1131541Srgrimes} 1141541Srgrimes 1151549Srgrimesvoid 1161541Srgrimesktrnamei(vp, path) 1171541Srgrimes struct vnode *vp; 1181541Srgrimes char *path; 1191541Srgrimes{ 1201541Srgrimes struct ktr_header *kth; 1211541Srgrimes struct proc *p = curproc; /* XXX */ 1221541Srgrimes 1231541Srgrimes p->p_traceflag |= KTRFAC_ACTIVE; 1241541Srgrimes kth = ktrgetheader(KTR_NAMEI); 1251541Srgrimes kth->ktr_len = strlen(path); 1261541Srgrimes kth->ktr_buf = path; 1271541Srgrimes 1281541Srgrimes ktrwrite(vp, kth); 1291541Srgrimes FREE(kth, M_TEMP); 1301541Srgrimes p->p_traceflag &= ~KTRFAC_ACTIVE; 1311541Srgrimes} 1321541Srgrimes 1331549Srgrimesvoid 1341541Srgrimesktrgenio(vp, fd, rw, iov, len, error) 1351541Srgrimes struct vnode *vp; 1361541Srgrimes int fd; 1371541Srgrimes enum uio_rw rw; 1381541Srgrimes register struct iovec *iov; 1391541Srgrimes int len, error; 1401541Srgrimes{ 1411541Srgrimes struct ktr_header *kth; 1421541Srgrimes register struct ktr_genio *ktp; 1431541Srgrimes register caddr_t cp; 1441541Srgrimes register int resid = len, cnt; 1451541Srgrimes struct proc *p = curproc; /* XXX */ 1468876Srgrimes 1471541Srgrimes if (error) 1481541Srgrimes return; 1491541Srgrimes p->p_traceflag |= KTRFAC_ACTIVE; 1501541Srgrimes kth = ktrgetheader(KTR_GENIO); 1511541Srgrimes MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, 1521541Srgrimes M_TEMP, M_WAITOK); 1531541Srgrimes ktp->ktr_fd = fd; 1541541Srgrimes ktp->ktr_rw = rw; 1551541Srgrimes cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); 1561541Srgrimes while (resid > 0) { 1571541Srgrimes if ((cnt = iov->iov_len) > resid) 1581541Srgrimes cnt = resid; 1591541Srgrimes if (copyin(iov->iov_base, cp, (unsigned)cnt)) 1601541Srgrimes goto done; 1611541Srgrimes cp += cnt; 1621541Srgrimes resid -= cnt; 1631541Srgrimes iov++; 1641541Srgrimes } 1651541Srgrimes kth->ktr_buf = (caddr_t)ktp; 1661541Srgrimes kth->ktr_len = sizeof (struct ktr_genio) + len; 1671541Srgrimes 1681541Srgrimes ktrwrite(vp, kth); 1691541Srgrimesdone: 1701541Srgrimes FREE(kth, M_TEMP); 1711541Srgrimes FREE(ktp, M_TEMP); 1721541Srgrimes p->p_traceflag &= ~KTRFAC_ACTIVE; 1731541Srgrimes} 1741541Srgrimes 1751549Srgrimesvoid 1761541Srgrimesktrpsig(vp, sig, action, mask, code) 1771541Srgrimes struct vnode *vp; 1781541Srgrimes int sig; 1791541Srgrimes sig_t action; 1801541Srgrimes int mask, code; 1811541Srgrimes{ 1821541Srgrimes struct ktr_header *kth; 1831541Srgrimes struct ktr_psig kp; 1841541Srgrimes struct proc *p = curproc; /* XXX */ 1851541Srgrimes 1861541Srgrimes p->p_traceflag |= KTRFAC_ACTIVE; 1871541Srgrimes kth = ktrgetheader(KTR_PSIG); 1881541Srgrimes kp.signo = (char)sig; 1891541Srgrimes kp.action = action; 1901541Srgrimes kp.mask = mask; 1911541Srgrimes kp.code = code; 1921541Srgrimes kth->ktr_buf = (caddr_t)&kp; 1931541Srgrimes kth->ktr_len = sizeof (struct ktr_psig); 1941541Srgrimes 1951541Srgrimes ktrwrite(vp, kth); 1961541Srgrimes FREE(kth, M_TEMP); 1971541Srgrimes p->p_traceflag &= ~KTRFAC_ACTIVE; 1981541Srgrimes} 1991541Srgrimes 2001549Srgrimesvoid 2011541Srgrimesktrcsw(vp, out, user) 2021541Srgrimes struct vnode *vp; 2031541Srgrimes int out, user; 2041541Srgrimes{ 2051541Srgrimes struct ktr_header *kth; 2061541Srgrimes struct ktr_csw kc; 2071541Srgrimes struct proc *p = curproc; /* XXX */ 2081541Srgrimes 2091541Srgrimes p->p_traceflag |= KTRFAC_ACTIVE; 2101541Srgrimes kth = ktrgetheader(KTR_CSW); 2111541Srgrimes kc.out = out; 2121541Srgrimes kc.user = user; 2131541Srgrimes kth->ktr_buf = (caddr_t)&kc; 2141541Srgrimes kth->ktr_len = sizeof (struct ktr_csw); 2151541Srgrimes 2161541Srgrimes ktrwrite(vp, kth); 2171541Srgrimes FREE(kth, M_TEMP); 2181541Srgrimes p->p_traceflag &= ~KTRFAC_ACTIVE; 2191541Srgrimes} 2201541Srgrimes 2211541Srgrimes/* Interface and common routines */ 2221541Srgrimes 2231541Srgrimes/* 2241541Srgrimes * ktrace system call 2251541Srgrimes */ 2261541Srgrimesstruct ktrace_args { 2271541Srgrimes char *fname; 2281541Srgrimes int ops; 2291541Srgrimes int facs; 2301541Srgrimes int pid; 2311541Srgrimes}; 2321541Srgrimes/* ARGSUSED */ 2331549Srgrimesint 2341541Srgrimesktrace(curp, uap, retval) 2351541Srgrimes struct proc *curp; 2361541Srgrimes register struct ktrace_args *uap; 2371541Srgrimes int *retval; 2381541Srgrimes{ 2391541Srgrimes register struct vnode *vp = NULL; 2401541Srgrimes register struct proc *p; 2411541Srgrimes struct pgrp *pg; 2421541Srgrimes int facs = uap->facs & ~KTRFAC_ROOT; 2431541Srgrimes int ops = KTROP(uap->ops); 2441541Srgrimes int descend = uap->ops & KTRFLAG_DESCEND; 2451541Srgrimes int ret = 0; 2461541Srgrimes int error = 0; 2471541Srgrimes struct nameidata nd; 2481541Srgrimes 2491541Srgrimes curp->p_traceflag |= KTRFAC_ACTIVE; 2501541Srgrimes if (ops != KTROP_CLEAR) { 2511541Srgrimes /* 2521541Srgrimes * an operation which requires a file argument. 2531541Srgrimes */ 2541541Srgrimes NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, curp); 2553308Sphk error = vn_open(&nd, FREAD|FWRITE, 0); 2563308Sphk if (error) { 2571541Srgrimes curp->p_traceflag &= ~KTRFAC_ACTIVE; 2581541Srgrimes return (error); 2591541Srgrimes } 2601541Srgrimes vp = nd.ni_vp; 2611541Srgrimes VOP_UNLOCK(vp); 2621541Srgrimes if (vp->v_type != VREG) { 2631541Srgrimes (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp); 2641541Srgrimes curp->p_traceflag &= ~KTRFAC_ACTIVE; 2651541Srgrimes return (EACCES); 2661541Srgrimes } 2671541Srgrimes } 2681541Srgrimes /* 2691541Srgrimes * Clear all uses of the tracefile 2701541Srgrimes */ 2711541Srgrimes if (ops == KTROP_CLEARFILE) { 2721541Srgrimes for (p = (struct proc *)allproc; p != NULL; p = p->p_next) { 2731541Srgrimes if (p->p_tracep == vp) { 2741541Srgrimes if (ktrcanset(curp, p)) { 2751541Srgrimes p->p_tracep = NULL; 2761541Srgrimes p->p_traceflag = 0; 2771541Srgrimes (void) vn_close(vp, FREAD|FWRITE, 2781541Srgrimes p->p_ucred, p); 2791541Srgrimes } else 2801541Srgrimes error = EPERM; 2811541Srgrimes } 2821541Srgrimes } 2831541Srgrimes goto done; 2841541Srgrimes } 2851541Srgrimes /* 2861541Srgrimes * need something to (un)trace (XXX - why is this here?) 2871541Srgrimes */ 2881541Srgrimes if (!facs) { 2891541Srgrimes error = EINVAL; 2901541Srgrimes goto done; 2911541Srgrimes } 2928876Srgrimes /* 2931541Srgrimes * do it 2941541Srgrimes */ 2951541Srgrimes if (uap->pid < 0) { 2961541Srgrimes /* 2971541Srgrimes * by process group 2981541Srgrimes */ 2991541Srgrimes pg = pgfind(-uap->pid); 3001541Srgrimes if (pg == NULL) { 3011541Srgrimes error = ESRCH; 3021541Srgrimes goto done; 3031541Srgrimes } 3041541Srgrimes for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) 3051541Srgrimes if (descend) 3061541Srgrimes ret |= ktrsetchildren(curp, p, ops, facs, vp); 3078876Srgrimes else 3081541Srgrimes ret |= ktrops(curp, p, ops, facs, vp); 3098876Srgrimes 3101541Srgrimes } else { 3111541Srgrimes /* 3121541Srgrimes * by pid 3131541Srgrimes */ 3141541Srgrimes p = pfind(uap->pid); 3151541Srgrimes if (p == NULL) { 3161541Srgrimes error = ESRCH; 3171541Srgrimes goto done; 3181541Srgrimes } 3191541Srgrimes if (descend) 3201541Srgrimes ret |= ktrsetchildren(curp, p, ops, facs, vp); 3211541Srgrimes else 3221541Srgrimes ret |= ktrops(curp, p, ops, facs, vp); 3231541Srgrimes } 3241541Srgrimes if (!ret) 3251541Srgrimes error = EPERM; 3261541Srgrimesdone: 3271541Srgrimes if (vp != NULL) 3281541Srgrimes (void) vn_close(vp, FWRITE, curp->p_ucred, curp); 3291541Srgrimes curp->p_traceflag &= ~KTRFAC_ACTIVE; 3301541Srgrimes return (error); 3311541Srgrimes} 3321541Srgrimes 3331541Srgrimesint 3341541Srgrimesktrops(curp, p, ops, facs, vp) 3351541Srgrimes struct proc *p, *curp; 3361541Srgrimes int ops, facs; 3371541Srgrimes struct vnode *vp; 3381541Srgrimes{ 3391541Srgrimes 3401541Srgrimes if (!ktrcanset(curp, p)) 3411541Srgrimes return (0); 3421541Srgrimes if (ops == KTROP_SET) { 3438876Srgrimes if (p->p_tracep != vp) { 3441541Srgrimes /* 3451541Srgrimes * if trace file already in use, relinquish 3461541Srgrimes */ 3471541Srgrimes if (p->p_tracep != NULL) 3481541Srgrimes vrele(p->p_tracep); 3491541Srgrimes VREF(vp); 3501541Srgrimes p->p_tracep = vp; 3511541Srgrimes } 3521541Srgrimes p->p_traceflag |= facs; 3531541Srgrimes if (curp->p_ucred->cr_uid == 0) 3541541Srgrimes p->p_traceflag |= KTRFAC_ROOT; 3558876Srgrimes } else { 3561541Srgrimes /* KTROP_CLEAR */ 3571541Srgrimes if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { 3581541Srgrimes /* no more tracing */ 3591541Srgrimes p->p_traceflag = 0; 3601541Srgrimes if (p->p_tracep != NULL) { 3611541Srgrimes vrele(p->p_tracep); 3621541Srgrimes p->p_tracep = NULL; 3631541Srgrimes } 3641541Srgrimes } 3651541Srgrimes } 3661541Srgrimes 3671541Srgrimes return (1); 3681541Srgrimes} 3691541Srgrimes 3701549Srgrimesint 3711541Srgrimesktrsetchildren(curp, top, ops, facs, vp) 3721541Srgrimes struct proc *curp, *top; 3731541Srgrimes int ops, facs; 3741541Srgrimes struct vnode *vp; 3751541Srgrimes{ 3761541Srgrimes register struct proc *p; 3771541Srgrimes register int ret = 0; 3781541Srgrimes 3791541Srgrimes p = top; 3801541Srgrimes for (;;) { 3811541Srgrimes ret |= ktrops(curp, p, ops, facs, vp); 3821541Srgrimes /* 3831541Srgrimes * If this process has children, descend to them next, 3841541Srgrimes * otherwise do any siblings, and if done with this level, 3851541Srgrimes * follow back up the tree (but not past top). 3861541Srgrimes */ 3871541Srgrimes if (p->p_cptr) 3881541Srgrimes p = p->p_cptr; 3891541Srgrimes else if (p == top) 3901541Srgrimes return (ret); 3911541Srgrimes else if (p->p_osptr) 3921541Srgrimes p = p->p_osptr; 3931541Srgrimes else for (;;) { 3941541Srgrimes p = p->p_pptr; 3951541Srgrimes if (p == top) 3961541Srgrimes return (ret); 3971541Srgrimes if (p->p_osptr) { 3981541Srgrimes p = p->p_osptr; 3991541Srgrimes break; 4001541Srgrimes } 4011541Srgrimes } 4021541Srgrimes } 4031541Srgrimes /*NOTREACHED*/ 4041541Srgrimes} 4051541Srgrimes 4061549Srgrimesvoid 4071541Srgrimesktrwrite(vp, kth) 4081541Srgrimes struct vnode *vp; 4091541Srgrimes register struct ktr_header *kth; 4101541Srgrimes{ 4111541Srgrimes struct uio auio; 4121541Srgrimes struct iovec aiov[2]; 4131541Srgrimes register struct proc *p = curproc; /* XXX */ 4141541Srgrimes int error; 4151541Srgrimes 4161541Srgrimes if (vp == NULL) 4171541Srgrimes return; 4181541Srgrimes auio.uio_iov = &aiov[0]; 4191541Srgrimes auio.uio_offset = 0; 4201541Srgrimes auio.uio_segflg = UIO_SYSSPACE; 4211541Srgrimes auio.uio_rw = UIO_WRITE; 4221541Srgrimes aiov[0].iov_base = (caddr_t)kth; 4231541Srgrimes aiov[0].iov_len = sizeof(struct ktr_header); 4241541Srgrimes auio.uio_resid = sizeof(struct ktr_header); 4251541Srgrimes auio.uio_iovcnt = 1; 4261541Srgrimes auio.uio_procp = (struct proc *)0; 4271541Srgrimes if (kth->ktr_len > 0) { 4281541Srgrimes auio.uio_iovcnt++; 4291541Srgrimes aiov[1].iov_base = kth->ktr_buf; 4301541Srgrimes aiov[1].iov_len = kth->ktr_len; 4311541Srgrimes auio.uio_resid += kth->ktr_len; 4321541Srgrimes } 4331541Srgrimes VOP_LOCK(vp); 4341541Srgrimes error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred); 4351541Srgrimes VOP_UNLOCK(vp); 4361541Srgrimes if (!error) 4371541Srgrimes return; 4381541Srgrimes /* 4391541Srgrimes * If error encountered, give up tracing on this vnode. 4401541Srgrimes */ 4411541Srgrimes log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", 4421541Srgrimes error); 4431541Srgrimes for (p = (struct proc *)allproc; p != NULL; p = p->p_next) { 4441541Srgrimes if (p->p_tracep == vp) { 4451541Srgrimes p->p_tracep = NULL; 4461541Srgrimes p->p_traceflag = 0; 4471541Srgrimes vrele(vp); 4481541Srgrimes } 4491541Srgrimes } 4501541Srgrimes} 4511541Srgrimes 4521541Srgrimes/* 4531541Srgrimes * Return true if caller has permission to set the ktracing state 4541541Srgrimes * of target. Essentially, the target can't possess any 4551541Srgrimes * more permissions than the caller. KTRFAC_ROOT signifies that 4568876Srgrimes * root previously set the tracing status on the target process, and 4571541Srgrimes * so, only root may further change it. 4581541Srgrimes * 4591541Srgrimes * TODO: check groups. use caller effective gid. 4601541Srgrimes */ 4611549Srgrimesint 4621541Srgrimesktrcanset(callp, targetp) 4631541Srgrimes struct proc *callp, *targetp; 4641541Srgrimes{ 4651541Srgrimes register struct pcred *caller = callp->p_cred; 4661541Srgrimes register struct pcred *target = targetp->p_cred; 4671541Srgrimes 4681541Srgrimes if ((caller->pc_ucred->cr_uid == target->p_ruid && 4691541Srgrimes target->p_ruid == target->p_svuid && 4701541Srgrimes caller->p_rgid == target->p_rgid && /* XXX */ 4711541Srgrimes target->p_rgid == target->p_svgid && 4721541Srgrimes (targetp->p_traceflag & KTRFAC_ROOT) == 0) || 4731541Srgrimes caller->pc_ucred->cr_uid == 0) 4741541Srgrimes return (1); 4751541Srgrimes 4761541Srgrimes return (0); 4771541Srgrimes} 4781541Srgrimes 4791541Srgrimes#endif 480