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> 41d2d3e875SBruce Evans #include <sys/sysproto.h> 421c5bb3eaSPeter Wemm #include <sys/kernel.h> 43df8bae1dSRodney W. Grimes #include <sys/proc.h> 443ac4d1efSBruce Evans #include <sys/fcntl.h> 451cd52ec3SBruce Evans #include <sys/lock.h> 46df8bae1dSRodney W. Grimes #include <sys/namei.h> 47df8bae1dSRodney W. Grimes #include <sys/vnode.h> 48df8bae1dSRodney W. Grimes #include <sys/ktrace.h> 49df8bae1dSRodney W. Grimes #include <sys/malloc.h> 501005a129SJohn Baldwin #include <sys/sx.h> 51df8bae1dSRodney W. Grimes #include <sys/syslog.h> 5291421ba2SRobert Watson #include <sys/jail.h> 53df8bae1dSRodney W. Grimes 54a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_KTRACE, "KTRACE", "KTRACE"); 5555166637SPoul-Henning Kamp 56db6a20e2SGarrett Wollman #ifdef KTRACE 5787b6de2bSPoul-Henning Kamp static struct ktr_header *ktrgetheader __P((int type)); 5842ebfbf2SBrian Feldman static void ktrwrite __P((struct vnode *, struct ktr_header *, struct uio *)); 5987b6de2bSPoul-Henning Kamp static int ktrcanset __P((struct proc *,struct proc *)); 6087b6de2bSPoul-Henning Kamp static int ktrsetchildren __P((struct proc *,struct proc *,int,int,struct vnode *)); 6187b6de2bSPoul-Henning Kamp static int ktrops __P((struct proc *,struct proc *,int,int,struct vnode *)); 6298d93822SBruce Evans 6387b6de2bSPoul-Henning Kamp 6487b6de2bSPoul-Henning Kamp static struct ktr_header * 65df8bae1dSRodney W. Grimes ktrgetheader(type) 66df8bae1dSRodney W. Grimes int type; 67df8bae1dSRodney W. Grimes { 68df8bae1dSRodney W. Grimes register struct ktr_header *kth; 69df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 70df8bae1dSRodney W. Grimes 71df8bae1dSRodney W. Grimes MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 72d1c4c866SPoul-Henning Kamp M_KTRACE, M_WAITOK); 73df8bae1dSRodney W. Grimes kth->ktr_type = type; 74df8bae1dSRodney W. Grimes microtime(&kth->ktr_time); 75df8bae1dSRodney W. Grimes kth->ktr_pid = p->p_pid; 7685fce0e4SMarcel Moolenaar bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN + 1); 77df8bae1dSRodney W. Grimes return (kth); 78df8bae1dSRodney W. Grimes } 79df8bae1dSRodney W. Grimes 8026f9a767SRodney W. Grimes void 81df8bae1dSRodney W. Grimes ktrsyscall(vp, code, narg, args) 82df8bae1dSRodney W. Grimes struct vnode *vp; 8371ddfdbbSDmitrij Tejblum int code, narg; 8471ddfdbbSDmitrij Tejblum register_t args[]; 85df8bae1dSRodney W. Grimes { 86df8bae1dSRodney W. Grimes struct ktr_header *kth; 87df8bae1dSRodney W. Grimes struct ktr_syscall *ktp; 8871ddfdbbSDmitrij Tejblum register int len = offsetof(struct ktr_syscall, ktr_args) + 8971ddfdbbSDmitrij Tejblum (narg * sizeof(register_t)); 90df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 9171ddfdbbSDmitrij Tejblum register_t *argp; 9271ddfdbbSDmitrij Tejblum int i; 93df8bae1dSRodney W. Grimes 94df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 95df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_SYSCALL); 96d1c4c866SPoul-Henning Kamp MALLOC(ktp, struct ktr_syscall *, len, M_KTRACE, M_WAITOK); 97df8bae1dSRodney W. Grimes ktp->ktr_code = code; 98df8bae1dSRodney W. Grimes ktp->ktr_narg = narg; 9971ddfdbbSDmitrij Tejblum argp = &ktp->ktr_args[0]; 100df8bae1dSRodney W. Grimes for (i = 0; i < narg; i++) 101df8bae1dSRodney W. Grimes *argp++ = args[i]; 10262ae6c89SJason Evans kth->ktr_buffer = (caddr_t)ktp; 103df8bae1dSRodney W. Grimes kth->ktr_len = len; 10442ebfbf2SBrian Feldman ktrwrite(vp, kth, NULL); 105d1c4c866SPoul-Henning Kamp FREE(ktp, M_KTRACE); 106d1c4c866SPoul-Henning Kamp FREE(kth, M_KTRACE); 107df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 108df8bae1dSRodney W. Grimes } 109df8bae1dSRodney W. Grimes 11026f9a767SRodney W. Grimes void 111df8bae1dSRodney W. Grimes ktrsysret(vp, code, error, retval) 112df8bae1dSRodney W. Grimes struct vnode *vp; 11371ddfdbbSDmitrij Tejblum int code, error; 11471ddfdbbSDmitrij Tejblum register_t retval; 115df8bae1dSRodney W. Grimes { 116df8bae1dSRodney W. Grimes struct ktr_header *kth; 117df8bae1dSRodney W. Grimes struct ktr_sysret ktp; 118df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 119df8bae1dSRodney W. Grimes 120df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 121df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_SYSRET); 122df8bae1dSRodney W. Grimes ktp.ktr_code = code; 123df8bae1dSRodney W. Grimes ktp.ktr_error = error; 124df8bae1dSRodney W. Grimes ktp.ktr_retval = retval; /* what about val2 ? */ 125df8bae1dSRodney W. Grimes 12662ae6c89SJason Evans kth->ktr_buffer = (caddr_t)&ktp; 127df8bae1dSRodney W. Grimes kth->ktr_len = sizeof(struct ktr_sysret); 128df8bae1dSRodney W. Grimes 12942ebfbf2SBrian Feldman ktrwrite(vp, kth, NULL); 130d1c4c866SPoul-Henning Kamp FREE(kth, M_KTRACE); 131df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 132df8bae1dSRodney W. Grimes } 133df8bae1dSRodney W. Grimes 13426f9a767SRodney W. Grimes void 135df8bae1dSRodney W. Grimes ktrnamei(vp, path) 136df8bae1dSRodney W. Grimes struct vnode *vp; 137df8bae1dSRodney W. Grimes char *path; 138df8bae1dSRodney W. Grimes { 139df8bae1dSRodney W. Grimes struct ktr_header *kth; 140df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 141df8bae1dSRodney W. Grimes 142df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 143df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_NAMEI); 144df8bae1dSRodney W. Grimes kth->ktr_len = strlen(path); 14562ae6c89SJason Evans kth->ktr_buffer = path; 146df8bae1dSRodney W. Grimes 14742ebfbf2SBrian Feldman ktrwrite(vp, kth, NULL); 148d1c4c866SPoul-Henning Kamp FREE(kth, M_KTRACE); 149df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 150df8bae1dSRodney W. Grimes } 151df8bae1dSRodney W. Grimes 15226f9a767SRodney W. Grimes void 15342ebfbf2SBrian Feldman ktrgenio(vp, fd, rw, uio, error) 154df8bae1dSRodney W. Grimes struct vnode *vp; 155df8bae1dSRodney W. Grimes int fd; 156df8bae1dSRodney W. Grimes enum uio_rw rw; 15742ebfbf2SBrian Feldman struct uio *uio; 15842ebfbf2SBrian Feldman int error; 159df8bae1dSRodney W. Grimes { 160df8bae1dSRodney W. Grimes struct ktr_header *kth; 16142ebfbf2SBrian Feldman struct ktr_genio ktg; 162df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 163df8bae1dSRodney W. Grimes 164df8bae1dSRodney W. Grimes if (error) 165df8bae1dSRodney W. Grimes return; 166df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 167df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_GENIO); 16842ebfbf2SBrian Feldman ktg.ktr_fd = fd; 16942ebfbf2SBrian Feldman ktg.ktr_rw = rw; 17062ae6c89SJason Evans kth->ktr_buffer = (caddr_t)&ktg; 17142ebfbf2SBrian Feldman kth->ktr_len = sizeof(struct ktr_genio); 17242ebfbf2SBrian Feldman uio->uio_offset = 0; 1739d1cfdceSBrian Feldman uio->uio_rw = UIO_WRITE; 174df8bae1dSRodney W. Grimes 17542ebfbf2SBrian Feldman ktrwrite(vp, kth, uio); 176d1c4c866SPoul-Henning Kamp FREE(kth, M_KTRACE); 177df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 178df8bae1dSRodney W. Grimes } 179df8bae1dSRodney W. Grimes 18026f9a767SRodney W. Grimes void 181df8bae1dSRodney W. Grimes ktrpsig(vp, sig, action, mask, code) 182df8bae1dSRodney W. Grimes struct vnode *vp; 183a93fdaacSMarcel Moolenaar int sig; 184df8bae1dSRodney W. Grimes sig_t action; 1852c42a146SMarcel Moolenaar sigset_t *mask; 186a93fdaacSMarcel Moolenaar int code; 187df8bae1dSRodney W. Grimes { 188df8bae1dSRodney W. Grimes struct ktr_header *kth; 189df8bae1dSRodney W. Grimes struct ktr_psig kp; 190df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 191df8bae1dSRodney W. Grimes 192df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 193df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_PSIG); 194df8bae1dSRodney W. Grimes kp.signo = (char)sig; 195df8bae1dSRodney W. Grimes kp.action = action; 1962c42a146SMarcel Moolenaar kp.mask = *mask; 197df8bae1dSRodney W. Grimes kp.code = code; 19862ae6c89SJason Evans kth->ktr_buffer = (caddr_t)&kp; 199df8bae1dSRodney W. Grimes kth->ktr_len = sizeof (struct ktr_psig); 200df8bae1dSRodney W. Grimes 20142ebfbf2SBrian Feldman ktrwrite(vp, kth, NULL); 202d1c4c866SPoul-Henning Kamp FREE(kth, M_KTRACE); 203df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 204df8bae1dSRodney W. Grimes } 205df8bae1dSRodney W. Grimes 20626f9a767SRodney W. Grimes void 207df8bae1dSRodney W. Grimes ktrcsw(vp, out, user) 208df8bae1dSRodney W. Grimes struct vnode *vp; 209df8bae1dSRodney W. Grimes int out, user; 210df8bae1dSRodney W. Grimes { 211df8bae1dSRodney W. Grimes struct ktr_header *kth; 212df8bae1dSRodney W. Grimes struct ktr_csw kc; 213df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 214df8bae1dSRodney W. Grimes 215df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 216df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_CSW); 217df8bae1dSRodney W. Grimes kc.out = out; 218df8bae1dSRodney W. Grimes kc.user = user; 21962ae6c89SJason Evans kth->ktr_buffer = (caddr_t)&kc; 220df8bae1dSRodney W. Grimes kth->ktr_len = sizeof (struct ktr_csw); 221df8bae1dSRodney W. Grimes 22242ebfbf2SBrian Feldman ktrwrite(vp, kth, NULL); 223d1c4c866SPoul-Henning Kamp FREE(kth, M_KTRACE); 224df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 225df8bae1dSRodney W. Grimes } 226db6a20e2SGarrett Wollman #endif 227df8bae1dSRodney W. Grimes 228df8bae1dSRodney W. Grimes /* Interface and common routines */ 229df8bae1dSRodney W. Grimes 230df8bae1dSRodney W. Grimes /* 231df8bae1dSRodney W. Grimes * ktrace system call 232df8bae1dSRodney W. Grimes */ 233d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 234df8bae1dSRodney W. Grimes struct ktrace_args { 235df8bae1dSRodney W. Grimes char *fname; 236df8bae1dSRodney W. Grimes int ops; 237df8bae1dSRodney W. Grimes int facs; 238df8bae1dSRodney W. Grimes int pid; 239df8bae1dSRodney W. Grimes }; 240d2d3e875SBruce Evans #endif 241df8bae1dSRodney W. Grimes /* ARGSUSED */ 24226f9a767SRodney W. Grimes int 243cb226aaaSPoul-Henning Kamp ktrace(curp, uap) 244df8bae1dSRodney W. Grimes struct proc *curp; 245df8bae1dSRodney W. Grimes register struct ktrace_args *uap; 246df8bae1dSRodney W. Grimes { 247db6a20e2SGarrett Wollman #ifdef KTRACE 248df8bae1dSRodney W. Grimes register struct vnode *vp = NULL; 249df8bae1dSRodney W. Grimes register struct proc *p; 250df8bae1dSRodney W. Grimes struct pgrp *pg; 251df8bae1dSRodney W. Grimes int facs = uap->facs & ~KTRFAC_ROOT; 252df8bae1dSRodney W. Grimes int ops = KTROP(uap->ops); 253df8bae1dSRodney W. Grimes int descend = uap->ops & KTRFLAG_DESCEND; 254df8bae1dSRodney W. Grimes int ret = 0; 255e6796b67SKirk McKusick int flags, error = 0; 256df8bae1dSRodney W. Grimes struct nameidata nd; 257df8bae1dSRodney W. Grimes 258df8bae1dSRodney W. Grimes curp->p_traceflag |= KTRFAC_ACTIVE; 259df8bae1dSRodney W. Grimes if (ops != KTROP_CLEAR) { 260df8bae1dSRodney W. Grimes /* 261df8bae1dSRodney W. Grimes * an operation which requires a file argument. 262df8bae1dSRodney W. Grimes */ 2638c0abefaSDima Ruban NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, curp); 264e6796b67SKirk McKusick flags = FREAD | FWRITE | O_NOFOLLOW; 265e6796b67SKirk McKusick error = vn_open(&nd, &flags, 0); 266797f2d22SPoul-Henning Kamp if (error) { 267df8bae1dSRodney W. Grimes curp->p_traceflag &= ~KTRFAC_ACTIVE; 268df8bae1dSRodney W. Grimes return (error); 269df8bae1dSRodney W. Grimes } 270762e6b85SEivind Eklund NDFREE(&nd, NDF_ONLY_PNBUF); 271df8bae1dSRodney W. Grimes vp = nd.ni_vp; 272996c772fSJohn Dyson VOP_UNLOCK(vp, 0, curp); 273df8bae1dSRodney W. Grimes if (vp->v_type != VREG) { 274df8bae1dSRodney W. Grimes (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp); 275df8bae1dSRodney W. Grimes curp->p_traceflag &= ~KTRFAC_ACTIVE; 276df8bae1dSRodney W. Grimes return (EACCES); 277df8bae1dSRodney W. Grimes } 278df8bae1dSRodney W. Grimes } 279df8bae1dSRodney W. Grimes /* 280df8bae1dSRodney W. Grimes * Clear all uses of the tracefile 281df8bae1dSRodney W. Grimes */ 282df8bae1dSRodney W. Grimes if (ops == KTROP_CLEARFILE) { 2831005a129SJohn Baldwin sx_slock(&allproc_lock); 2842e3c8fcbSPoul-Henning Kamp LIST_FOREACH(p, &allproc, p_list) { 285df8bae1dSRodney W. Grimes if (p->p_tracep == vp) { 286df8bae1dSRodney W. Grimes if (ktrcanset(curp, p)) { 287df8bae1dSRodney W. Grimes p->p_tracep = NULL; 288df8bae1dSRodney W. Grimes p->p_traceflag = 0; 289df8bae1dSRodney W. Grimes (void) vn_close(vp, FREAD|FWRITE, 290df8bae1dSRodney W. Grimes p->p_ucred, p); 291df8bae1dSRodney W. Grimes } else 292df8bae1dSRodney W. Grimes error = EPERM; 293df8bae1dSRodney W. Grimes } 294df8bae1dSRodney W. Grimes } 2951005a129SJohn Baldwin sx_sunlock(&allproc_lock); 296df8bae1dSRodney W. Grimes goto done; 297df8bae1dSRodney W. Grimes } 298df8bae1dSRodney W. Grimes /* 299df8bae1dSRodney W. Grimes * need something to (un)trace (XXX - why is this here?) 300df8bae1dSRodney W. Grimes */ 301df8bae1dSRodney W. Grimes if (!facs) { 302df8bae1dSRodney W. Grimes error = EINVAL; 303df8bae1dSRodney W. Grimes goto done; 304df8bae1dSRodney W. Grimes } 305df8bae1dSRodney W. Grimes /* 306df8bae1dSRodney W. Grimes * do it 307df8bae1dSRodney W. Grimes */ 308df8bae1dSRodney W. Grimes if (uap->pid < 0) { 309df8bae1dSRodney W. Grimes /* 310df8bae1dSRodney W. Grimes * by process group 311df8bae1dSRodney W. Grimes */ 312df8bae1dSRodney W. Grimes pg = pgfind(-uap->pid); 313df8bae1dSRodney W. Grimes if (pg == NULL) { 314df8bae1dSRodney W. Grimes error = ESRCH; 315df8bae1dSRodney W. Grimes goto done; 316df8bae1dSRodney W. Grimes } 3172e3c8fcbSPoul-Henning Kamp LIST_FOREACH(p, &pg->pg_members, p_pglist) 318df8bae1dSRodney W. Grimes if (descend) 319df8bae1dSRodney W. Grimes ret |= ktrsetchildren(curp, p, ops, facs, vp); 320df8bae1dSRodney W. Grimes else 321df8bae1dSRodney W. Grimes ret |= ktrops(curp, p, ops, facs, vp); 322df8bae1dSRodney W. Grimes } else { 323df8bae1dSRodney W. Grimes /* 324df8bae1dSRodney W. Grimes * by pid 325df8bae1dSRodney W. Grimes */ 326df8bae1dSRodney W. Grimes p = pfind(uap->pid); 327df8bae1dSRodney W. Grimes if (p == NULL) { 328df8bae1dSRodney W. Grimes error = ESRCH; 329df8bae1dSRodney W. Grimes goto done; 330df8bae1dSRodney W. Grimes } 331df8bae1dSRodney W. Grimes if (descend) 332df8bae1dSRodney W. Grimes ret |= ktrsetchildren(curp, p, ops, facs, vp); 333df8bae1dSRodney W. Grimes else 334df8bae1dSRodney W. Grimes ret |= ktrops(curp, p, ops, facs, vp); 335df8bae1dSRodney W. Grimes } 336df8bae1dSRodney W. Grimes if (!ret) 337df8bae1dSRodney W. Grimes error = EPERM; 338df8bae1dSRodney W. Grimes done: 339df8bae1dSRodney W. Grimes if (vp != NULL) 340df8bae1dSRodney W. Grimes (void) vn_close(vp, FWRITE, curp->p_ucred, curp); 341df8bae1dSRodney W. Grimes curp->p_traceflag &= ~KTRFAC_ACTIVE; 342df8bae1dSRodney W. Grimes return (error); 343db6a20e2SGarrett Wollman #else 344db6a20e2SGarrett Wollman return ENOSYS; 345db6a20e2SGarrett Wollman #endif 346df8bae1dSRodney W. Grimes } 347df8bae1dSRodney W. Grimes 348e6c4b9baSPoul-Henning Kamp /* 349e6c4b9baSPoul-Henning Kamp * utrace system call 350e6c4b9baSPoul-Henning Kamp */ 351e6c4b9baSPoul-Henning Kamp /* ARGSUSED */ 352e6c4b9baSPoul-Henning Kamp int 353cb226aaaSPoul-Henning Kamp utrace(curp, uap) 354e6c4b9baSPoul-Henning Kamp struct proc *curp; 355e6c4b9baSPoul-Henning Kamp register struct utrace_args *uap; 356e6c4b9baSPoul-Henning Kamp { 357e6c4b9baSPoul-Henning Kamp #ifdef KTRACE 358e6c4b9baSPoul-Henning Kamp struct ktr_header *kth; 359e6c4b9baSPoul-Henning Kamp struct proc *p = curproc; /* XXX */ 360e6c4b9baSPoul-Henning Kamp register caddr_t cp; 361e6c4b9baSPoul-Henning Kamp 362e6c4b9baSPoul-Henning Kamp if (!KTRPOINT(p, KTR_USER)) 363e6c4b9baSPoul-Henning Kamp return (0); 364bdfa4f04SAlfred Perlstein if (uap->len > KTR_USER_MAXLEN) 3650bad156aSAlfred Perlstein return (EINVAL); 366e6c4b9baSPoul-Henning Kamp p->p_traceflag |= KTRFAC_ACTIVE; 367e6c4b9baSPoul-Henning Kamp kth = ktrgetheader(KTR_USER); 368d920a829SPoul-Henning Kamp MALLOC(cp, caddr_t, uap->len, M_KTRACE, M_WAITOK); 369e6c4b9baSPoul-Henning Kamp if (!copyin(uap->addr, cp, uap->len)) { 37062ae6c89SJason Evans kth->ktr_buffer = cp; 371d920a829SPoul-Henning Kamp kth->ktr_len = uap->len; 37242ebfbf2SBrian Feldman ktrwrite(p->p_tracep, kth, NULL); 373e6c4b9baSPoul-Henning Kamp } 374e6c4b9baSPoul-Henning Kamp FREE(kth, M_KTRACE); 375d920a829SPoul-Henning Kamp FREE(cp, M_KTRACE); 376e6c4b9baSPoul-Henning Kamp p->p_traceflag &= ~KTRFAC_ACTIVE; 377e6c4b9baSPoul-Henning Kamp 378e6c4b9baSPoul-Henning Kamp return (0); 379e6c4b9baSPoul-Henning Kamp #else 380e6c4b9baSPoul-Henning Kamp return (ENOSYS); 381e6c4b9baSPoul-Henning Kamp #endif 382e6c4b9baSPoul-Henning Kamp } 383e6c4b9baSPoul-Henning Kamp 384db6a20e2SGarrett Wollman #ifdef KTRACE 38587b6de2bSPoul-Henning Kamp static int 386df8bae1dSRodney W. Grimes ktrops(curp, p, ops, facs, vp) 387df8bae1dSRodney W. Grimes struct proc *p, *curp; 388df8bae1dSRodney W. Grimes int ops, facs; 389df8bae1dSRodney W. Grimes struct vnode *vp; 390df8bae1dSRodney W. Grimes { 391df8bae1dSRodney W. Grimes 392df8bae1dSRodney W. Grimes if (!ktrcanset(curp, p)) 393df8bae1dSRodney W. Grimes return (0); 394df8bae1dSRodney W. Grimes if (ops == KTROP_SET) { 395df8bae1dSRodney W. Grimes if (p->p_tracep != vp) { 396df8bae1dSRodney W. Grimes /* 397df8bae1dSRodney W. Grimes * if trace file already in use, relinquish 398df8bae1dSRodney W. Grimes */ 399df8bae1dSRodney W. Grimes if (p->p_tracep != NULL) 400df8bae1dSRodney W. Grimes vrele(p->p_tracep); 401df8bae1dSRodney W. Grimes VREF(vp); 402df8bae1dSRodney W. Grimes p->p_tracep = vp; 403df8bae1dSRodney W. Grimes } 404df8bae1dSRodney W. Grimes p->p_traceflag |= facs; 405df8bae1dSRodney W. Grimes if (curp->p_ucred->cr_uid == 0) 406df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ROOT; 407df8bae1dSRodney W. Grimes } else { 408df8bae1dSRodney W. Grimes /* KTROP_CLEAR */ 409df8bae1dSRodney W. Grimes if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { 410df8bae1dSRodney W. Grimes /* no more tracing */ 411df8bae1dSRodney W. Grimes p->p_traceflag = 0; 412df8bae1dSRodney W. Grimes if (p->p_tracep != NULL) { 413df8bae1dSRodney W. Grimes vrele(p->p_tracep); 414df8bae1dSRodney W. Grimes p->p_tracep = NULL; 415df8bae1dSRodney W. Grimes } 416df8bae1dSRodney W. Grimes } 417df8bae1dSRodney W. Grimes } 418df8bae1dSRodney W. Grimes 419df8bae1dSRodney W. Grimes return (1); 420df8bae1dSRodney W. Grimes } 421df8bae1dSRodney W. Grimes 42287b6de2bSPoul-Henning Kamp static int 423df8bae1dSRodney W. Grimes ktrsetchildren(curp, top, ops, facs, vp) 424df8bae1dSRodney W. Grimes struct proc *curp, *top; 425df8bae1dSRodney W. Grimes int ops, facs; 426df8bae1dSRodney W. Grimes struct vnode *vp; 427df8bae1dSRodney W. Grimes { 428df8bae1dSRodney W. Grimes register struct proc *p; 429df8bae1dSRodney W. Grimes register int ret = 0; 430df8bae1dSRodney W. Grimes 431df8bae1dSRodney W. Grimes p = top; 4321005a129SJohn Baldwin sx_slock(&proctree_lock); 433df8bae1dSRodney W. Grimes for (;;) { 434df8bae1dSRodney W. Grimes ret |= ktrops(curp, p, ops, facs, vp); 435df8bae1dSRodney W. Grimes /* 436df8bae1dSRodney W. Grimes * If this process has children, descend to them next, 437df8bae1dSRodney W. Grimes * otherwise do any siblings, and if done with this level, 438df8bae1dSRodney W. Grimes * follow back up the tree (but not past top). 439df8bae1dSRodney W. Grimes */ 4402e3c8fcbSPoul-Henning Kamp if (!LIST_EMPTY(&p->p_children)) 4412e3c8fcbSPoul-Henning Kamp p = LIST_FIRST(&p->p_children); 442df8bae1dSRodney W. Grimes else for (;;) { 44398f03f90SJake Burkholder if (p == top) { 4441005a129SJohn Baldwin sx_sunlock(&proctree_lock); 445df8bae1dSRodney W. Grimes return (ret); 44698f03f90SJake Burkholder } 4472e3c8fcbSPoul-Henning Kamp if (LIST_NEXT(p, p_sibling)) { 4482e3c8fcbSPoul-Henning Kamp p = LIST_NEXT(p, p_sibling); 449df8bae1dSRodney W. Grimes break; 450df8bae1dSRodney W. Grimes } 451b75356e1SJeffrey Hsu p = p->p_pptr; 452df8bae1dSRodney W. Grimes } 453df8bae1dSRodney W. Grimes } 454df8bae1dSRodney W. Grimes /*NOTREACHED*/ 455df8bae1dSRodney W. Grimes } 456df8bae1dSRodney W. Grimes 45787b6de2bSPoul-Henning Kamp static void 45842ebfbf2SBrian Feldman ktrwrite(vp, kth, uio) 459df8bae1dSRodney W. Grimes struct vnode *vp; 460df8bae1dSRodney W. Grimes register struct ktr_header *kth; 46142ebfbf2SBrian Feldman struct uio *uio; 462df8bae1dSRodney W. Grimes { 463df8bae1dSRodney W. Grimes struct uio auio; 464df8bae1dSRodney W. Grimes struct iovec aiov[2]; 465f2a2857bSKirk McKusick struct proc *p = curproc; /* XXX */ 466f2a2857bSKirk McKusick struct mount *mp; 467df8bae1dSRodney W. Grimes int error; 468df8bae1dSRodney W. Grimes 469df8bae1dSRodney W. Grimes if (vp == NULL) 470df8bae1dSRodney W. Grimes return; 471df8bae1dSRodney W. Grimes auio.uio_iov = &aiov[0]; 472df8bae1dSRodney W. Grimes auio.uio_offset = 0; 473df8bae1dSRodney W. Grimes auio.uio_segflg = UIO_SYSSPACE; 474df8bae1dSRodney W. Grimes auio.uio_rw = UIO_WRITE; 475df8bae1dSRodney W. Grimes aiov[0].iov_base = (caddr_t)kth; 476df8bae1dSRodney W. Grimes aiov[0].iov_len = sizeof(struct ktr_header); 477df8bae1dSRodney W. Grimes auio.uio_resid = sizeof(struct ktr_header); 478df8bae1dSRodney W. Grimes auio.uio_iovcnt = 1; 479efb73e5aSRobert V. Baron auio.uio_procp = curproc; 480df8bae1dSRodney W. Grimes if (kth->ktr_len > 0) { 481df8bae1dSRodney W. Grimes auio.uio_iovcnt++; 48262ae6c89SJason Evans aiov[1].iov_base = kth->ktr_buffer; 483df8bae1dSRodney W. Grimes aiov[1].iov_len = kth->ktr_len; 484df8bae1dSRodney W. Grimes auio.uio_resid += kth->ktr_len; 48542ebfbf2SBrian Feldman if (uio != NULL) 48642ebfbf2SBrian Feldman kth->ktr_len += uio->uio_resid; 487df8bae1dSRodney W. Grimes } 488f2a2857bSKirk McKusick vn_start_write(vp, &mp, V_WAIT); 489996c772fSJohn Dyson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 49042ebfbf2SBrian Feldman (void)VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 491df8bae1dSRodney W. Grimes error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, p->p_ucred); 49242ebfbf2SBrian Feldman if (error == 0 && uio != NULL) { 49342ebfbf2SBrian Feldman (void)VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); 49442ebfbf2SBrian Feldman error = VOP_WRITE(vp, uio, IO_UNIT | IO_APPEND, p->p_ucred); 49542ebfbf2SBrian Feldman } 496996c772fSJohn Dyson VOP_UNLOCK(vp, 0, p); 497f2a2857bSKirk McKusick vn_finished_write(mp); 498df8bae1dSRodney W. Grimes if (!error) 499df8bae1dSRodney W. Grimes return; 500df8bae1dSRodney W. Grimes /* 501df8bae1dSRodney W. Grimes * If error encountered, give up tracing on this vnode. 502df8bae1dSRodney W. Grimes */ 503df8bae1dSRodney W. Grimes log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", 504df8bae1dSRodney W. Grimes error); 5051005a129SJohn Baldwin sx_slock(&allproc_lock); 5062e3c8fcbSPoul-Henning Kamp LIST_FOREACH(p, &allproc, p_list) { 507df8bae1dSRodney W. Grimes if (p->p_tracep == vp) { 508df8bae1dSRodney W. Grimes p->p_tracep = NULL; 509df8bae1dSRodney W. Grimes p->p_traceflag = 0; 510df8bae1dSRodney W. Grimes vrele(vp); 511df8bae1dSRodney W. Grimes } 512df8bae1dSRodney W. Grimes } 5131005a129SJohn Baldwin sx_sunlock(&allproc_lock); 514df8bae1dSRodney W. Grimes } 515df8bae1dSRodney W. Grimes 516df8bae1dSRodney W. Grimes /* 517df8bae1dSRodney W. Grimes * Return true if caller has permission to set the ktracing state 518df8bae1dSRodney W. Grimes * of target. Essentially, the target can't possess any 519df8bae1dSRodney W. Grimes * more permissions than the caller. KTRFAC_ROOT signifies that 520df8bae1dSRodney W. Grimes * root previously set the tracing status on the target process, and 521df8bae1dSRodney W. Grimes * so, only root may further change it. 522df8bae1dSRodney W. Grimes * 523387d2c03SRobert Watson * XXX: These checks are stronger than for ptrace() 52491421ba2SRobert Watson * XXX: This check should be p_can(... P_CAN_DEBUG ...); 525387d2c03SRobert Watson * 526df8bae1dSRodney W. Grimes * TODO: check groups. use caller effective gid. 527df8bae1dSRodney W. Grimes */ 52887b6de2bSPoul-Henning Kamp static int 529df8bae1dSRodney W. Grimes ktrcanset(callp, targetp) 530df8bae1dSRodney W. Grimes struct proc *callp, *targetp; 531df8bae1dSRodney W. Grimes { 532df8bae1dSRodney W. Grimes register struct pcred *caller = callp->p_cred; 533df8bae1dSRodney W. Grimes register struct pcred *target = targetp->p_cred; 534df8bae1dSRodney W. Grimes 53591421ba2SRobert Watson if (prison_check(callp->p_ucred, targetp->p_ucred)) 53675c13541SPoul-Henning Kamp return (0); 537df8bae1dSRodney W. Grimes if ((caller->pc_ucred->cr_uid == target->p_ruid && 538df8bae1dSRodney W. Grimes target->p_ruid == target->p_svuid && 539df8bae1dSRodney W. Grimes caller->p_rgid == target->p_rgid && /* XXX */ 540df8bae1dSRodney W. Grimes target->p_rgid == target->p_svgid && 541df8bae1dSRodney W. Grimes (targetp->p_traceflag & KTRFAC_ROOT) == 0) || 542df8bae1dSRodney W. Grimes caller->pc_ucred->cr_uid == 0) 543df8bae1dSRodney W. Grimes return (1); 544df8bae1dSRodney W. Grimes 545df8bae1dSRodney W. Grimes return (0); 546df8bae1dSRodney W. Grimes } 547df8bae1dSRodney W. Grimes 548db6a20e2SGarrett Wollman #endif /* KTRACE */ 549