1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1989, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33df8bae1dSRodney W. Grimes * @(#)kern_ktrace.c 8.2 (Berkeley) 9/23/93 34c3aac50fSPeter Wemm * $FreeBSD$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37db6a20e2SGarrett Wollman #include "opt_ktrace.h" 38df8bae1dSRodney W. Grimes 39df8bae1dSRodney W. Grimes #include <sys/param.h> 40f23b4c91SGarrett Wollman #include <sys/systm.h> 41fb919e4dSMark Murray #include <sys/lock.h> 42fb919e4dSMark Murray #include <sys/mutex.h> 43d2d3e875SBruce Evans #include <sys/sysproto.h> 441c5bb3eaSPeter Wemm #include <sys/kernel.h> 45df8bae1dSRodney W. Grimes #include <sys/proc.h> 463ac4d1efSBruce Evans #include <sys/fcntl.h> 47df8bae1dSRodney W. Grimes #include <sys/namei.h> 48df8bae1dSRodney W. Grimes #include <sys/vnode.h> 49df8bae1dSRodney W. Grimes #include <sys/ktrace.h> 50df8bae1dSRodney W. Grimes #include <sys/malloc.h> 511005a129SJohn Baldwin #include <sys/sx.h> 52df8bae1dSRodney W. Grimes #include <sys/syslog.h> 5391421ba2SRobert Watson #include <sys/jail.h> 54df8bae1dSRodney W. Grimes 55a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_KTRACE, "KTRACE", "KTRACE"); 5655166637SPoul-Henning Kamp 57db6a20e2SGarrett Wollman #ifdef KTRACE 584d77a549SAlfred Perlstein static struct ktr_header *ktrgetheader(int type); 594d77a549SAlfred Perlstein static void ktrwrite(struct vnode *, struct ktr_header *, struct uio *); 60a7ff7443SJohn Baldwin static int ktrcanset(struct thread *, struct proc *); 61a7ff7443SJohn Baldwin static int ktrsetchildren(struct thread *, struct proc *, int, int, struct vnode *); 62a7ff7443SJohn Baldwin static int ktrops(struct thread *, struct proc *, int, int, struct vnode *); 6398d93822SBruce Evans 6487b6de2bSPoul-Henning Kamp 6587b6de2bSPoul-Henning Kamp static struct ktr_header * 66df8bae1dSRodney W. Grimes ktrgetheader(type) 67df8bae1dSRodney W. Grimes int type; 68df8bae1dSRodney W. Grimes { 69df8bae1dSRodney W. Grimes register struct ktr_header *kth; 70df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 71df8bae1dSRodney W. Grimes 72df8bae1dSRodney W. Grimes MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 73d1c4c866SPoul-Henning Kamp M_KTRACE, M_WAITOK); 74df8bae1dSRodney W. Grimes kth->ktr_type = type; 75df8bae1dSRodney W. Grimes microtime(&kth->ktr_time); 76df8bae1dSRodney W. Grimes kth->ktr_pid = p->p_pid; 7785fce0e4SMarcel Moolenaar bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN + 1); 78df8bae1dSRodney W. Grimes return (kth); 79df8bae1dSRodney W. Grimes } 80df8bae1dSRodney W. Grimes 81356861dbSMatthew Dillon /* 82356861dbSMatthew Dillon * MPSAFE 83356861dbSMatthew Dillon */ 8426f9a767SRodney W. Grimes void 85df8bae1dSRodney W. Grimes ktrsyscall(vp, code, narg, args) 86df8bae1dSRodney W. Grimes struct vnode *vp; 8771ddfdbbSDmitrij Tejblum int code, narg; 8871ddfdbbSDmitrij Tejblum register_t args[]; 89df8bae1dSRodney W. Grimes { 90df8bae1dSRodney W. Grimes struct ktr_header *kth; 91df8bae1dSRodney W. Grimes struct ktr_syscall *ktp; 9271ddfdbbSDmitrij Tejblum register int len = offsetof(struct ktr_syscall, ktr_args) + 9371ddfdbbSDmitrij Tejblum (narg * sizeof(register_t)); 94df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 9571ddfdbbSDmitrij Tejblum register_t *argp; 9671ddfdbbSDmitrij Tejblum int i; 97df8bae1dSRodney W. Grimes 98356861dbSMatthew Dillon mtx_lock(&Giant); 99df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 100df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_SYSCALL); 101d1c4c866SPoul-Henning Kamp MALLOC(ktp, struct ktr_syscall *, len, M_KTRACE, M_WAITOK); 102df8bae1dSRodney W. Grimes ktp->ktr_code = code; 103df8bae1dSRodney W. Grimes ktp->ktr_narg = narg; 10471ddfdbbSDmitrij Tejblum argp = &ktp->ktr_args[0]; 105df8bae1dSRodney W. Grimes for (i = 0; i < narg; i++) 106df8bae1dSRodney W. Grimes *argp++ = args[i]; 10762ae6c89SJason Evans kth->ktr_buffer = (caddr_t)ktp; 108df8bae1dSRodney W. Grimes kth->ktr_len = len; 10942ebfbf2SBrian Feldman ktrwrite(vp, kth, NULL); 110d1c4c866SPoul-Henning Kamp FREE(ktp, M_KTRACE); 111d1c4c866SPoul-Henning Kamp FREE(kth, M_KTRACE); 112df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 113356861dbSMatthew Dillon mtx_unlock(&Giant); 114df8bae1dSRodney W. Grimes } 115df8bae1dSRodney W. Grimes 116356861dbSMatthew Dillon /* 117356861dbSMatthew Dillon * MPSAFE 118356861dbSMatthew Dillon */ 11926f9a767SRodney W. Grimes void 120df8bae1dSRodney W. Grimes ktrsysret(vp, code, error, retval) 121df8bae1dSRodney W. Grimes struct vnode *vp; 12271ddfdbbSDmitrij Tejblum int code, error; 12371ddfdbbSDmitrij Tejblum register_t retval; 124df8bae1dSRodney W. Grimes { 125df8bae1dSRodney W. Grimes struct ktr_header *kth; 126df8bae1dSRodney W. Grimes struct ktr_sysret ktp; 127df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 128df8bae1dSRodney W. Grimes 129356861dbSMatthew Dillon mtx_lock(&Giant); 130df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 131df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_SYSRET); 132df8bae1dSRodney W. Grimes ktp.ktr_code = code; 133df8bae1dSRodney W. Grimes ktp.ktr_error = error; 134df8bae1dSRodney W. Grimes ktp.ktr_retval = retval; /* what about val2 ? */ 135df8bae1dSRodney W. Grimes 13662ae6c89SJason Evans kth->ktr_buffer = (caddr_t)&ktp; 137df8bae1dSRodney W. Grimes kth->ktr_len = sizeof(struct ktr_sysret); 138df8bae1dSRodney W. Grimes 13942ebfbf2SBrian Feldman ktrwrite(vp, kth, NULL); 140d1c4c866SPoul-Henning Kamp FREE(kth, M_KTRACE); 141df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 142356861dbSMatthew Dillon mtx_unlock(&Giant); 143df8bae1dSRodney W. Grimes } 144df8bae1dSRodney W. Grimes 14526f9a767SRodney W. Grimes void 146df8bae1dSRodney W. Grimes ktrnamei(vp, path) 147df8bae1dSRodney W. Grimes struct vnode *vp; 148df8bae1dSRodney W. Grimes char *path; 149df8bae1dSRodney W. Grimes { 150df8bae1dSRodney W. Grimes struct ktr_header *kth; 151df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 152df8bae1dSRodney W. Grimes 15379deba82SMatthew Dillon /* 15479deba82SMatthew Dillon * don't let p_tracep get ripped out from under us 15579deba82SMatthew Dillon */ 15679deba82SMatthew Dillon if (vp) 15779deba82SMatthew Dillon VREF(vp); 158df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 159df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_NAMEI); 160df8bae1dSRodney W. Grimes kth->ktr_len = strlen(path); 16162ae6c89SJason Evans kth->ktr_buffer = path; 162df8bae1dSRodney W. Grimes 16342ebfbf2SBrian Feldman ktrwrite(vp, kth, NULL); 16479deba82SMatthew Dillon if (vp) 16579deba82SMatthew Dillon vrele(vp); 166d1c4c866SPoul-Henning Kamp FREE(kth, M_KTRACE); 167df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 168df8bae1dSRodney W. Grimes } 169df8bae1dSRodney W. Grimes 17026f9a767SRodney W. Grimes void 17142ebfbf2SBrian Feldman ktrgenio(vp, fd, rw, uio, error) 172df8bae1dSRodney W. Grimes struct vnode *vp; 173df8bae1dSRodney W. Grimes int fd; 174df8bae1dSRodney W. Grimes enum uio_rw rw; 17542ebfbf2SBrian Feldman struct uio *uio; 17642ebfbf2SBrian Feldman int error; 177df8bae1dSRodney W. Grimes { 178df8bae1dSRodney W. Grimes struct ktr_header *kth; 17942ebfbf2SBrian Feldman struct ktr_genio ktg; 180df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 181df8bae1dSRodney W. Grimes 182df8bae1dSRodney W. Grimes if (error) 183df8bae1dSRodney W. Grimes return; 184628abf6cSAlfred Perlstein 185628abf6cSAlfred Perlstein mtx_lock(&Giant); 18679deba82SMatthew Dillon /* 18779deba82SMatthew Dillon * don't let p_tracep get ripped out from under us 18879deba82SMatthew Dillon */ 18979deba82SMatthew Dillon if (vp) 19079deba82SMatthew Dillon VREF(vp); 191df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 192df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_GENIO); 19342ebfbf2SBrian Feldman ktg.ktr_fd = fd; 19442ebfbf2SBrian Feldman ktg.ktr_rw = rw; 19562ae6c89SJason Evans kth->ktr_buffer = (caddr_t)&ktg; 19642ebfbf2SBrian Feldman kth->ktr_len = sizeof(struct ktr_genio); 19742ebfbf2SBrian Feldman uio->uio_offset = 0; 1989d1cfdceSBrian Feldman uio->uio_rw = UIO_WRITE; 199df8bae1dSRodney W. Grimes 20042ebfbf2SBrian Feldman ktrwrite(vp, kth, uio); 20179deba82SMatthew Dillon if (vp) 20279deba82SMatthew Dillon vrele(vp); 203d1c4c866SPoul-Henning Kamp FREE(kth, M_KTRACE); 204df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 205628abf6cSAlfred Perlstein mtx_unlock(&Giant); 206df8bae1dSRodney W. Grimes } 207df8bae1dSRodney W. Grimes 20826f9a767SRodney W. Grimes void 209df8bae1dSRodney W. Grimes ktrpsig(vp, sig, action, mask, code) 210df8bae1dSRodney W. Grimes struct vnode *vp; 211a93fdaacSMarcel Moolenaar int sig; 212df8bae1dSRodney W. Grimes sig_t action; 2132c42a146SMarcel Moolenaar sigset_t *mask; 214a93fdaacSMarcel Moolenaar int code; 215df8bae1dSRodney W. Grimes { 216df8bae1dSRodney W. Grimes struct ktr_header *kth; 217df8bae1dSRodney W. Grimes struct ktr_psig kp; 218df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 219df8bae1dSRodney W. Grimes 22079deba82SMatthew Dillon /* 22179deba82SMatthew Dillon * don't let vp get ripped out from under us 22279deba82SMatthew Dillon */ 22379deba82SMatthew Dillon if (vp) 22479deba82SMatthew Dillon VREF(vp); 225df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 226df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_PSIG); 227df8bae1dSRodney W. Grimes kp.signo = (char)sig; 228df8bae1dSRodney W. Grimes kp.action = action; 2292c42a146SMarcel Moolenaar kp.mask = *mask; 230df8bae1dSRodney W. Grimes kp.code = code; 23162ae6c89SJason Evans kth->ktr_buffer = (caddr_t)&kp; 232df8bae1dSRodney W. Grimes kth->ktr_len = sizeof (struct ktr_psig); 233df8bae1dSRodney W. Grimes 23442ebfbf2SBrian Feldman ktrwrite(vp, kth, NULL); 23579deba82SMatthew Dillon if (vp) 23679deba82SMatthew Dillon vrele(vp); 237d1c4c866SPoul-Henning Kamp FREE(kth, M_KTRACE); 238df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 239df8bae1dSRodney W. Grimes } 240df8bae1dSRodney W. Grimes 24126f9a767SRodney W. Grimes void 242df8bae1dSRodney W. Grimes ktrcsw(vp, out, user) 243df8bae1dSRodney W. Grimes struct vnode *vp; 244df8bae1dSRodney W. Grimes int out, user; 245df8bae1dSRodney W. Grimes { 246df8bae1dSRodney W. Grimes struct ktr_header *kth; 247df8bae1dSRodney W. Grimes struct ktr_csw kc; 248df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 249df8bae1dSRodney W. Grimes 25079deba82SMatthew Dillon /* 25179deba82SMatthew Dillon * don't let vp get ripped out from under us 25279deba82SMatthew Dillon */ 25379deba82SMatthew Dillon if (vp) 25479deba82SMatthew Dillon VREF(vp); 255df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 256df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_CSW); 257df8bae1dSRodney W. Grimes kc.out = out; 258df8bae1dSRodney W. Grimes kc.user = user; 25962ae6c89SJason Evans kth->ktr_buffer = (caddr_t)&kc; 260df8bae1dSRodney W. Grimes kth->ktr_len = sizeof (struct ktr_csw); 261df8bae1dSRodney W. Grimes 26242ebfbf2SBrian Feldman ktrwrite(vp, kth, NULL); 26379deba82SMatthew Dillon if (vp) 26479deba82SMatthew Dillon vrele(vp); 265d1c4c866SPoul-Henning Kamp FREE(kth, M_KTRACE); 266df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 267df8bae1dSRodney W. Grimes } 268db6a20e2SGarrett Wollman #endif 269df8bae1dSRodney W. Grimes 270df8bae1dSRodney W. Grimes /* Interface and common routines */ 271df8bae1dSRodney W. Grimes 272df8bae1dSRodney W. Grimes /* 273df8bae1dSRodney W. Grimes * ktrace system call 274df8bae1dSRodney W. Grimes */ 275d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 276df8bae1dSRodney W. Grimes struct ktrace_args { 277df8bae1dSRodney W. Grimes char *fname; 278df8bae1dSRodney W. Grimes int ops; 279df8bae1dSRodney W. Grimes int facs; 280df8bae1dSRodney W. Grimes int pid; 281df8bae1dSRodney W. Grimes }; 282d2d3e875SBruce Evans #endif 283df8bae1dSRodney W. Grimes /* ARGSUSED */ 28426f9a767SRodney W. Grimes int 285b40ce416SJulian Elischer ktrace(td, uap) 286b40ce416SJulian Elischer struct thread *td; 287df8bae1dSRodney W. Grimes register struct ktrace_args *uap; 288df8bae1dSRodney W. Grimes { 289db6a20e2SGarrett Wollman #ifdef KTRACE 290b40ce416SJulian Elischer struct proc *curp = td->td_proc; 291df8bae1dSRodney W. Grimes register struct vnode *vp = NULL; 292df8bae1dSRodney W. Grimes register struct proc *p; 293df8bae1dSRodney W. Grimes struct pgrp *pg; 294df8bae1dSRodney W. Grimes int facs = uap->facs & ~KTRFAC_ROOT; 295df8bae1dSRodney W. Grimes int ops = KTROP(uap->ops); 296df8bae1dSRodney W. Grimes int descend = uap->ops & KTRFLAG_DESCEND; 297df8bae1dSRodney W. Grimes int ret = 0; 298e6796b67SKirk McKusick int flags, error = 0; 299df8bae1dSRodney W. Grimes struct nameidata nd; 300df8bae1dSRodney W. Grimes 301df8bae1dSRodney W. Grimes curp->p_traceflag |= KTRFAC_ACTIVE; 302df8bae1dSRodney W. Grimes if (ops != KTROP_CLEAR) { 303df8bae1dSRodney W. Grimes /* 304df8bae1dSRodney W. Grimes * an operation which requires a file argument. 305df8bae1dSRodney W. Grimes */ 306b40ce416SJulian Elischer NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, td); 307e6796b67SKirk McKusick flags = FREAD | FWRITE | O_NOFOLLOW; 308e6796b67SKirk McKusick error = vn_open(&nd, &flags, 0); 309797f2d22SPoul-Henning Kamp if (error) { 310df8bae1dSRodney W. Grimes curp->p_traceflag &= ~KTRFAC_ACTIVE; 311df8bae1dSRodney W. Grimes return (error); 312df8bae1dSRodney W. Grimes } 313762e6b85SEivind Eklund NDFREE(&nd, NDF_ONLY_PNBUF); 314df8bae1dSRodney W. Grimes vp = nd.ni_vp; 315b40ce416SJulian Elischer VOP_UNLOCK(vp, 0, td); 316df8bae1dSRodney W. Grimes if (vp->v_type != VREG) { 317a854ed98SJohn Baldwin (void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td); 318df8bae1dSRodney W. Grimes curp->p_traceflag &= ~KTRFAC_ACTIVE; 319df8bae1dSRodney W. Grimes return (EACCES); 320df8bae1dSRodney W. Grimes } 321df8bae1dSRodney W. Grimes } 322df8bae1dSRodney W. Grimes /* 32379deba82SMatthew Dillon * Clear all uses of the tracefile. 324df8bae1dSRodney W. Grimes */ 325df8bae1dSRodney W. Grimes if (ops == KTROP_CLEARFILE) { 3261005a129SJohn Baldwin sx_slock(&allproc_lock); 3272e3c8fcbSPoul-Henning Kamp LIST_FOREACH(p, &allproc, p_list) { 328a7ff7443SJohn Baldwin PROC_LOCK(p); 329df8bae1dSRodney W. Grimes if (p->p_tracep == vp) { 330a7ff7443SJohn Baldwin if (ktrcanset(td, p) && p->p_tracep == vp) { 331df8bae1dSRodney W. Grimes p->p_tracep = NULL; 332df8bae1dSRodney W. Grimes p->p_traceflag = 0; 333a7ff7443SJohn Baldwin PROC_UNLOCK(p); 334df8bae1dSRodney W. Grimes (void) vn_close(vp, FREAD|FWRITE, 335a854ed98SJohn Baldwin td->td_ucred, td); 33679deba82SMatthew Dillon } else { 337a7ff7443SJohn Baldwin PROC_UNLOCK(p); 338df8bae1dSRodney W. Grimes error = EPERM; 339df8bae1dSRodney W. Grimes } 340a7ff7443SJohn Baldwin } else 341a7ff7443SJohn Baldwin PROC_UNLOCK(p); 34279deba82SMatthew Dillon } 3431005a129SJohn Baldwin sx_sunlock(&allproc_lock); 344df8bae1dSRodney W. Grimes goto done; 345df8bae1dSRodney W. Grimes } 346df8bae1dSRodney W. Grimes /* 347df8bae1dSRodney W. Grimes * need something to (un)trace (XXX - why is this here?) 348df8bae1dSRodney W. Grimes */ 349df8bae1dSRodney W. Grimes if (!facs) { 350df8bae1dSRodney W. Grimes error = EINVAL; 351df8bae1dSRodney W. Grimes goto done; 352df8bae1dSRodney W. Grimes } 353df8bae1dSRodney W. Grimes /* 354df8bae1dSRodney W. Grimes * do it 355df8bae1dSRodney W. Grimes */ 356df8bae1dSRodney W. Grimes if (uap->pid < 0) { 357df8bae1dSRodney W. Grimes /* 358df8bae1dSRodney W. Grimes * by process group 359df8bae1dSRodney W. Grimes */ 360ba626c1dSJohn Baldwin sx_slock(&proctree_lock); 361df8bae1dSRodney W. Grimes pg = pgfind(-uap->pid); 362df8bae1dSRodney W. Grimes if (pg == NULL) { 363ba626c1dSJohn Baldwin sx_sunlock(&proctree_lock); 364df8bae1dSRodney W. Grimes error = ESRCH; 365df8bae1dSRodney W. Grimes goto done; 366df8bae1dSRodney W. Grimes } 367f591779bSSeigo Tanimura /* 368f591779bSSeigo Tanimura * ktrops() may call vrele(). Lock pg_members 369ba626c1dSJohn Baldwin * by the proctree_lock rather than pg_mtx. 370f591779bSSeigo Tanimura */ 371f591779bSSeigo Tanimura PGRP_UNLOCK(pg); 3722e3c8fcbSPoul-Henning Kamp LIST_FOREACH(p, &pg->pg_members, p_pglist) 373df8bae1dSRodney W. Grimes if (descend) 374a7ff7443SJohn Baldwin ret |= ktrsetchildren(td, p, ops, facs, vp); 375df8bae1dSRodney W. Grimes else 376a7ff7443SJohn Baldwin ret |= ktrops(td, p, ops, facs, vp); 377ba626c1dSJohn Baldwin sx_sunlock(&proctree_lock); 378df8bae1dSRodney W. Grimes } else { 379df8bae1dSRodney W. Grimes /* 380df8bae1dSRodney W. Grimes * by pid 381df8bae1dSRodney W. Grimes */ 382df8bae1dSRodney W. Grimes p = pfind(uap->pid); 383df8bae1dSRodney W. Grimes if (p == NULL) { 384df8bae1dSRodney W. Grimes error = ESRCH; 385df8bae1dSRodney W. Grimes goto done; 386df8bae1dSRodney W. Grimes } 38733a9ed9dSJohn Baldwin PROC_UNLOCK(p); 388a7ff7443SJohn Baldwin /* XXX: UNLOCK above has a race */ 389df8bae1dSRodney W. Grimes if (descend) 390a7ff7443SJohn Baldwin ret |= ktrsetchildren(td, p, ops, facs, vp); 391df8bae1dSRodney W. Grimes else 392a7ff7443SJohn Baldwin ret |= ktrops(td, p, ops, facs, vp); 393df8bae1dSRodney W. Grimes } 394df8bae1dSRodney W. Grimes if (!ret) 395df8bae1dSRodney W. Grimes error = EPERM; 396df8bae1dSRodney W. Grimes done: 397df8bae1dSRodney W. Grimes if (vp != NULL) 398a854ed98SJohn Baldwin (void) vn_close(vp, FWRITE, td->td_ucred, td); 399df8bae1dSRodney W. Grimes curp->p_traceflag &= ~KTRFAC_ACTIVE; 400df8bae1dSRodney W. Grimes return (error); 401db6a20e2SGarrett Wollman #else 402db6a20e2SGarrett Wollman return ENOSYS; 403db6a20e2SGarrett Wollman #endif 404df8bae1dSRodney W. Grimes } 405df8bae1dSRodney W. Grimes 406e6c4b9baSPoul-Henning Kamp /* 407e6c4b9baSPoul-Henning Kamp * utrace system call 408e6c4b9baSPoul-Henning Kamp */ 409e6c4b9baSPoul-Henning Kamp /* ARGSUSED */ 410e6c4b9baSPoul-Henning Kamp int 411b40ce416SJulian Elischer utrace(td, uap) 412b40ce416SJulian Elischer struct thread *td; 413e6c4b9baSPoul-Henning Kamp register struct utrace_args *uap; 414e6c4b9baSPoul-Henning Kamp { 415b40ce416SJulian Elischer 416e6c4b9baSPoul-Henning Kamp #ifdef KTRACE 417e6c4b9baSPoul-Henning Kamp struct ktr_header *kth; 418e6c4b9baSPoul-Henning Kamp struct proc *p = curproc; /* XXX */ 41979deba82SMatthew Dillon struct vnode *vp; 420e6c4b9baSPoul-Henning Kamp register caddr_t cp; 421e6c4b9baSPoul-Henning Kamp 422e6c4b9baSPoul-Henning Kamp if (!KTRPOINT(p, KTR_USER)) 423e6c4b9baSPoul-Henning Kamp return (0); 424bdfa4f04SAlfred Perlstein if (uap->len > KTR_USER_MAXLEN) 4250bad156aSAlfred Perlstein return (EINVAL); 426e6c4b9baSPoul-Henning Kamp p->p_traceflag |= KTRFAC_ACTIVE; 42779deba82SMatthew Dillon if ((vp = p->p_tracep) != NULL) 42879deba82SMatthew Dillon VREF(vp); 429e6c4b9baSPoul-Henning Kamp kth = ktrgetheader(KTR_USER); 430d920a829SPoul-Henning Kamp MALLOC(cp, caddr_t, uap->len, M_KTRACE, M_WAITOK); 431e6c4b9baSPoul-Henning Kamp if (!copyin(uap->addr, cp, uap->len)) { 43262ae6c89SJason Evans kth->ktr_buffer = cp; 433d920a829SPoul-Henning Kamp kth->ktr_len = uap->len; 43479deba82SMatthew Dillon ktrwrite(vp, kth, NULL); 435e6c4b9baSPoul-Henning Kamp } 43679deba82SMatthew Dillon if (vp) 43779deba82SMatthew Dillon vrele(vp); 438e6c4b9baSPoul-Henning Kamp FREE(kth, M_KTRACE); 439d920a829SPoul-Henning Kamp FREE(cp, M_KTRACE); 440e6c4b9baSPoul-Henning Kamp p->p_traceflag &= ~KTRFAC_ACTIVE; 441e6c4b9baSPoul-Henning Kamp 442e6c4b9baSPoul-Henning Kamp return (0); 443e6c4b9baSPoul-Henning Kamp #else 444e6c4b9baSPoul-Henning Kamp return (ENOSYS); 445e6c4b9baSPoul-Henning Kamp #endif 446e6c4b9baSPoul-Henning Kamp } 447e6c4b9baSPoul-Henning Kamp 448db6a20e2SGarrett Wollman #ifdef KTRACE 44987b6de2bSPoul-Henning Kamp static int 450a7ff7443SJohn Baldwin ktrops(td, p, ops, facs, vp) 451a7ff7443SJohn Baldwin struct thread *td; 452a7ff7443SJohn Baldwin struct proc *p; 453df8bae1dSRodney W. Grimes int ops, facs; 454df8bae1dSRodney W. Grimes struct vnode *vp; 455df8bae1dSRodney W. Grimes { 456a7ff7443SJohn Baldwin struct vnode *vtmp = NULL, *newvp = NULL; 457df8bae1dSRodney W. Grimes 458a7ff7443SJohn Baldwin PROC_LOCK(p); 459a7ff7443SJohn Baldwin if (!ktrcanset(td, p)) { 460a7ff7443SJohn Baldwin PROC_UNLOCK(p); 461df8bae1dSRodney W. Grimes return (0); 462a7ff7443SJohn Baldwin } 463df8bae1dSRodney W. Grimes if (ops == KTROP_SET) { 464df8bae1dSRodney W. Grimes if (p->p_tracep != vp) { 46579deba82SMatthew Dillon struct vnode *vtmp; 46679deba82SMatthew Dillon 467df8bae1dSRodney W. Grimes /* 468a7ff7443SJohn Baldwin * if trace file already in use, relinquish below 469df8bae1dSRodney W. Grimes */ 470a7ff7443SJohn Baldwin newvp = vp; 471a7ff7443SJohn Baldwin vtmp = p->p_tracep; 47279deba82SMatthew Dillon p->p_tracep = NULL; 473df8bae1dSRodney W. Grimes } 474df8bae1dSRodney W. Grimes p->p_traceflag |= facs; 475a7ff7443SJohn Baldwin if (td->td_ucred->cr_uid == 0) 476df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ROOT; 477df8bae1dSRodney W. Grimes } else { 478df8bae1dSRodney W. Grimes /* KTROP_CLEAR */ 479df8bae1dSRodney W. Grimes if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { 48079deba82SMatthew Dillon struct vnode *vtmp; 48179deba82SMatthew Dillon 482df8bae1dSRodney W. Grimes /* no more tracing */ 483df8bae1dSRodney W. Grimes p->p_traceflag = 0; 484a7ff7443SJohn Baldwin vtmp = p->p_tracep; 485df8bae1dSRodney W. Grimes p->p_tracep = NULL; 486a7ff7443SJohn Baldwin } 487a7ff7443SJohn Baldwin } 488a7ff7443SJohn Baldwin PROC_UNLOCK(p); 489a7ff7443SJohn Baldwin 490a7ff7443SJohn Baldwin /* Release old trace file if requested. */ 491a7ff7443SJohn Baldwin if (vtmp != NULL) 49279deba82SMatthew Dillon vrele(vtmp); 493a7ff7443SJohn Baldwin 494a7ff7443SJohn Baldwin /* Setup new trace file if requested. */ 495a7ff7443SJohn Baldwin /* 496a7ff7443SJohn Baldwin * XXX: Doing this before the PROC_UNLOCK above would result in 497a7ff7443SJohn Baldwin * fewer lock operations but would break old behavior where the 498a7ff7443SJohn Baldwin * above vrele() would not be traced when changing trace files. 499a7ff7443SJohn Baldwin */ 500a7ff7443SJohn Baldwin if (newvp != NULL) { 501a7ff7443SJohn Baldwin VREF(newvp); 502a7ff7443SJohn Baldwin PROC_LOCK(p); 503a7ff7443SJohn Baldwin p->p_tracep = newvp; 504a7ff7443SJohn Baldwin PROC_UNLOCK(p); 505df8bae1dSRodney W. Grimes } 506df8bae1dSRodney W. Grimes 507df8bae1dSRodney W. Grimes return (1); 508df8bae1dSRodney W. Grimes } 509df8bae1dSRodney W. Grimes 51087b6de2bSPoul-Henning Kamp static int 511a7ff7443SJohn Baldwin ktrsetchildren(td, top, ops, facs, vp) 512a7ff7443SJohn Baldwin struct thread *td; 513a7ff7443SJohn Baldwin struct proc *top; 514df8bae1dSRodney W. Grimes int ops, facs; 515df8bae1dSRodney W. Grimes struct vnode *vp; 516df8bae1dSRodney W. Grimes { 517df8bae1dSRodney W. Grimes register struct proc *p; 518df8bae1dSRodney W. Grimes register int ret = 0; 519df8bae1dSRodney W. Grimes 520df8bae1dSRodney W. Grimes p = top; 5211005a129SJohn Baldwin sx_slock(&proctree_lock); 522df8bae1dSRodney W. Grimes for (;;) { 523a7ff7443SJohn Baldwin ret |= ktrops(td, p, ops, facs, vp); 524df8bae1dSRodney W. Grimes /* 525df8bae1dSRodney W. Grimes * If this process has children, descend to them next, 526df8bae1dSRodney W. Grimes * otherwise do any siblings, and if done with this level, 527df8bae1dSRodney W. Grimes * follow back up the tree (but not past top). 528df8bae1dSRodney W. Grimes */ 5292e3c8fcbSPoul-Henning Kamp if (!LIST_EMPTY(&p->p_children)) 5302e3c8fcbSPoul-Henning Kamp p = LIST_FIRST(&p->p_children); 531df8bae1dSRodney W. Grimes else for (;;) { 53298f03f90SJake Burkholder if (p == top) { 5331005a129SJohn Baldwin sx_sunlock(&proctree_lock); 534df8bae1dSRodney W. Grimes return (ret); 53598f03f90SJake Burkholder } 5362e3c8fcbSPoul-Henning Kamp if (LIST_NEXT(p, p_sibling)) { 5372e3c8fcbSPoul-Henning Kamp p = LIST_NEXT(p, p_sibling); 538df8bae1dSRodney W. Grimes break; 539df8bae1dSRodney W. Grimes } 540b75356e1SJeffrey Hsu p = p->p_pptr; 541df8bae1dSRodney W. Grimes } 542df8bae1dSRodney W. Grimes } 543df8bae1dSRodney W. Grimes /*NOTREACHED*/ 544df8bae1dSRodney W. Grimes } 545df8bae1dSRodney W. Grimes 54687b6de2bSPoul-Henning Kamp static void 54742ebfbf2SBrian Feldman ktrwrite(vp, kth, uio) 548df8bae1dSRodney W. Grimes struct vnode *vp; 549df8bae1dSRodney W. Grimes register struct ktr_header *kth; 55042ebfbf2SBrian Feldman struct uio *uio; 551df8bae1dSRodney W. Grimes { 552df8bae1dSRodney W. Grimes struct uio auio; 553df8bae1dSRodney W. Grimes struct iovec aiov[2]; 554b40ce416SJulian Elischer struct thread *td = curthread; /* XXX */ 555b40ce416SJulian Elischer struct proc *p = td->td_proc; /* XXX */ 556f2a2857bSKirk McKusick struct mount *mp; 557df8bae1dSRodney W. Grimes int error; 558df8bae1dSRodney W. Grimes 559df8bae1dSRodney W. Grimes if (vp == NULL) 560df8bae1dSRodney W. Grimes return; 561df8bae1dSRodney W. Grimes auio.uio_iov = &aiov[0]; 562df8bae1dSRodney W. Grimes auio.uio_offset = 0; 563df8bae1dSRodney W. Grimes auio.uio_segflg = UIO_SYSSPACE; 564df8bae1dSRodney W. Grimes auio.uio_rw = UIO_WRITE; 565df8bae1dSRodney W. Grimes aiov[0].iov_base = (caddr_t)kth; 566df8bae1dSRodney W. Grimes aiov[0].iov_len = sizeof(struct ktr_header); 567df8bae1dSRodney W. Grimes auio.uio_resid = sizeof(struct ktr_header); 568df8bae1dSRodney W. Grimes auio.uio_iovcnt = 1; 569b40ce416SJulian Elischer auio.uio_td = curthread; 570df8bae1dSRodney W. Grimes if (kth->ktr_len > 0) { 571df8bae1dSRodney W. Grimes auio.uio_iovcnt++; 57262ae6c89SJason Evans aiov[1].iov_base = kth->ktr_buffer; 573df8bae1dSRodney W. Grimes aiov[1].iov_len = kth->ktr_len; 574df8bae1dSRodney W. Grimes auio.uio_resid += kth->ktr_len; 57542ebfbf2SBrian Feldman if (uio != NULL) 57642ebfbf2SBrian Feldman kth->ktr_len += uio->uio_resid; 577df8bae1dSRodney W. Grimes } 578f2a2857bSKirk McKusick vn_start_write(vp, &mp, V_WAIT); 579b40ce416SJulian Elischer vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 580a854ed98SJohn Baldwin (void)VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 581a854ed98SJohn Baldwin error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, td->td_ucred); 58242ebfbf2SBrian Feldman if (error == 0 && uio != NULL) { 583a854ed98SJohn Baldwin (void)VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); 584a854ed98SJohn Baldwin error = VOP_WRITE(vp, uio, IO_UNIT | IO_APPEND, td->td_ucred); 58542ebfbf2SBrian Feldman } 586b40ce416SJulian Elischer VOP_UNLOCK(vp, 0, td); 587f2a2857bSKirk McKusick vn_finished_write(mp); 588df8bae1dSRodney W. Grimes if (!error) 589df8bae1dSRodney W. Grimes return; 590df8bae1dSRodney W. Grimes /* 59179deba82SMatthew Dillon * If error encountered, give up tracing on this vnode. XXX what 59279deba82SMatthew Dillon * happens to the loop if vrele() blocks? 593df8bae1dSRodney W. Grimes */ 594df8bae1dSRodney W. Grimes log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", 595df8bae1dSRodney W. Grimes error); 5961005a129SJohn Baldwin sx_slock(&allproc_lock); 5972e3c8fcbSPoul-Henning Kamp LIST_FOREACH(p, &allproc, p_list) { 598df8bae1dSRodney W. Grimes if (p->p_tracep == vp) { 599df8bae1dSRodney W. Grimes p->p_tracep = NULL; 600df8bae1dSRodney W. Grimes p->p_traceflag = 0; 601df8bae1dSRodney W. Grimes vrele(vp); 602df8bae1dSRodney W. Grimes } 603df8bae1dSRodney W. Grimes } 6041005a129SJohn Baldwin sx_sunlock(&allproc_lock); 605df8bae1dSRodney W. Grimes } 606df8bae1dSRodney W. Grimes 607df8bae1dSRodney W. Grimes /* 608df8bae1dSRodney W. Grimes * Return true if caller has permission to set the ktracing state 609df8bae1dSRodney W. Grimes * of target. Essentially, the target can't possess any 610df8bae1dSRodney W. Grimes * more permissions than the caller. KTRFAC_ROOT signifies that 611df8bae1dSRodney W. Grimes * root previously set the tracing status on the target process, and 612df8bae1dSRodney W. Grimes * so, only root may further change it. 613df8bae1dSRodney W. Grimes */ 61487b6de2bSPoul-Henning Kamp static int 615a7ff7443SJohn Baldwin ktrcanset(td, targetp) 616a7ff7443SJohn Baldwin struct thread *td; 617a7ff7443SJohn Baldwin struct proc *targetp; 618df8bae1dSRodney W. Grimes { 619df8bae1dSRodney W. Grimes 620a7ff7443SJohn Baldwin PROC_LOCK_ASSERT(targetp, MA_OWNED); 621a0f75161SRobert Watson if (targetp->p_traceflag & KTRFAC_ROOT && 622a7ff7443SJohn Baldwin suser_cred(td->td_ucred, PRISON_ROOT)) 62375c13541SPoul-Henning Kamp return (0); 624a0f75161SRobert Watson 625f44d9e24SJohn Baldwin if (p_candebug(td, targetp) != 0) 626a0f75161SRobert Watson return (0); 627a0f75161SRobert Watson 628df8bae1dSRodney W. Grimes return (1); 629df8bae1dSRodney W. Grimes } 630df8bae1dSRodney W. Grimes 631db6a20e2SGarrett Wollman #endif /* KTRACE */ 632