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 34df8bae1dSRodney W. Grimes */ 35df8bae1dSRodney W. Grimes 36df8bae1dSRodney W. Grimes #ifdef KTRACE 37df8bae1dSRodney W. Grimes 38df8bae1dSRodney W. Grimes #include <sys/param.h> 39df8bae1dSRodney W. Grimes #include <sys/proc.h> 40df8bae1dSRodney W. Grimes #include <sys/file.h> 41df8bae1dSRodney W. Grimes #include <sys/namei.h> 42df8bae1dSRodney W. Grimes #include <sys/vnode.h> 43df8bae1dSRodney W. Grimes #include <sys/ktrace.h> 44df8bae1dSRodney W. Grimes #include <sys/malloc.h> 45df8bae1dSRodney W. Grimes #include <sys/syslog.h> 46df8bae1dSRodney W. Grimes 4726f9a767SRodney W. Grimes void ktrwrite __P((struct vnode *, struct ktr_header *)); 4826f9a767SRodney W. Grimes 49df8bae1dSRodney W. Grimes struct ktr_header * 50df8bae1dSRodney W. Grimes ktrgetheader(type) 51df8bae1dSRodney W. Grimes int type; 52df8bae1dSRodney W. Grimes { 53df8bae1dSRodney W. Grimes register struct ktr_header *kth; 54df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 55df8bae1dSRodney W. Grimes 56df8bae1dSRodney W. Grimes MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 57df8bae1dSRodney W. Grimes M_TEMP, M_WAITOK); 58df8bae1dSRodney W. Grimes kth->ktr_type = type; 59df8bae1dSRodney W. Grimes microtime(&kth->ktr_time); 60df8bae1dSRodney W. Grimes kth->ktr_pid = p->p_pid; 61df8bae1dSRodney W. Grimes bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN); 62df8bae1dSRodney W. Grimes return (kth); 63df8bae1dSRodney W. Grimes } 64df8bae1dSRodney W. Grimes 6526f9a767SRodney W. Grimes void 66df8bae1dSRodney W. Grimes ktrsyscall(vp, code, narg, args) 67df8bae1dSRodney W. Grimes struct vnode *vp; 68df8bae1dSRodney W. Grimes int code, narg, args[]; 69df8bae1dSRodney W. Grimes { 70df8bae1dSRodney W. Grimes struct ktr_header *kth; 71df8bae1dSRodney W. Grimes struct ktr_syscall *ktp; 72df8bae1dSRodney W. Grimes register len = sizeof(struct ktr_syscall) + (narg * sizeof(int)); 73df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 74df8bae1dSRodney W. Grimes int *argp, i; 75df8bae1dSRodney W. Grimes 76df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 77df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_SYSCALL); 78df8bae1dSRodney W. Grimes MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); 79df8bae1dSRodney W. Grimes ktp->ktr_code = code; 80df8bae1dSRodney W. Grimes ktp->ktr_narg = narg; 81df8bae1dSRodney W. Grimes argp = (int *)((char *)ktp + sizeof(struct ktr_syscall)); 82df8bae1dSRodney W. Grimes for (i = 0; i < narg; i++) 83df8bae1dSRodney W. Grimes *argp++ = args[i]; 84df8bae1dSRodney W. Grimes kth->ktr_buf = (caddr_t)ktp; 85df8bae1dSRodney W. Grimes kth->ktr_len = len; 86df8bae1dSRodney W. Grimes ktrwrite(vp, kth); 87df8bae1dSRodney W. Grimes FREE(ktp, M_TEMP); 88df8bae1dSRodney W. Grimes FREE(kth, M_TEMP); 89df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 90df8bae1dSRodney W. Grimes } 91df8bae1dSRodney W. Grimes 9226f9a767SRodney W. Grimes void 93df8bae1dSRodney W. Grimes ktrsysret(vp, code, error, retval) 94df8bae1dSRodney W. Grimes struct vnode *vp; 95df8bae1dSRodney W. Grimes int code, error, retval; 96df8bae1dSRodney W. Grimes { 97df8bae1dSRodney W. Grimes struct ktr_header *kth; 98df8bae1dSRodney W. Grimes struct ktr_sysret ktp; 99df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 100df8bae1dSRodney W. Grimes 101df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 102df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_SYSRET); 103df8bae1dSRodney W. Grimes ktp.ktr_code = code; 104df8bae1dSRodney W. Grimes ktp.ktr_error = error; 105df8bae1dSRodney W. Grimes ktp.ktr_retval = retval; /* what about val2 ? */ 106df8bae1dSRodney W. Grimes 107df8bae1dSRodney W. Grimes kth->ktr_buf = (caddr_t)&ktp; 108df8bae1dSRodney W. Grimes kth->ktr_len = sizeof(struct ktr_sysret); 109df8bae1dSRodney W. Grimes 110df8bae1dSRodney W. Grimes ktrwrite(vp, kth); 111df8bae1dSRodney W. Grimes FREE(kth, M_TEMP); 112df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 113df8bae1dSRodney W. Grimes } 114df8bae1dSRodney W. Grimes 11526f9a767SRodney W. Grimes void 116df8bae1dSRodney W. Grimes ktrnamei(vp, path) 117df8bae1dSRodney W. Grimes struct vnode *vp; 118df8bae1dSRodney W. Grimes char *path; 119df8bae1dSRodney W. Grimes { 120df8bae1dSRodney W. Grimes struct ktr_header *kth; 121df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 122df8bae1dSRodney W. Grimes 123df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 124df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_NAMEI); 125df8bae1dSRodney W. Grimes kth->ktr_len = strlen(path); 126df8bae1dSRodney W. Grimes kth->ktr_buf = path; 127df8bae1dSRodney W. Grimes 128df8bae1dSRodney W. Grimes ktrwrite(vp, kth); 129df8bae1dSRodney W. Grimes FREE(kth, M_TEMP); 130df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 131df8bae1dSRodney W. Grimes } 132df8bae1dSRodney W. Grimes 13326f9a767SRodney W. Grimes void 134df8bae1dSRodney W. Grimes ktrgenio(vp, fd, rw, iov, len, error) 135df8bae1dSRodney W. Grimes struct vnode *vp; 136df8bae1dSRodney W. Grimes int fd; 137df8bae1dSRodney W. Grimes enum uio_rw rw; 138df8bae1dSRodney W. Grimes register struct iovec *iov; 139df8bae1dSRodney W. Grimes int len, error; 140df8bae1dSRodney W. Grimes { 141df8bae1dSRodney W. Grimes struct ktr_header *kth; 142df8bae1dSRodney W. Grimes register struct ktr_genio *ktp; 143df8bae1dSRodney W. Grimes register caddr_t cp; 144df8bae1dSRodney W. Grimes register int resid = len, cnt; 145df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 146df8bae1dSRodney W. Grimes 147df8bae1dSRodney W. Grimes if (error) 148df8bae1dSRodney W. Grimes return; 149df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 150df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_GENIO); 151df8bae1dSRodney W. Grimes MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, 152df8bae1dSRodney W. Grimes M_TEMP, M_WAITOK); 153df8bae1dSRodney W. Grimes ktp->ktr_fd = fd; 154df8bae1dSRodney W. Grimes ktp->ktr_rw = rw; 155df8bae1dSRodney W. Grimes cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); 156df8bae1dSRodney W. Grimes while (resid > 0) { 157df8bae1dSRodney W. Grimes if ((cnt = iov->iov_len) > resid) 158df8bae1dSRodney W. Grimes cnt = resid; 159df8bae1dSRodney W. Grimes if (copyin(iov->iov_base, cp, (unsigned)cnt)) 160df8bae1dSRodney W. Grimes goto done; 161df8bae1dSRodney W. Grimes cp += cnt; 162df8bae1dSRodney W. Grimes resid -= cnt; 163df8bae1dSRodney W. Grimes iov++; 164df8bae1dSRodney W. Grimes } 165df8bae1dSRodney W. Grimes kth->ktr_buf = (caddr_t)ktp; 166df8bae1dSRodney W. Grimes kth->ktr_len = sizeof (struct ktr_genio) + len; 167df8bae1dSRodney W. Grimes 168df8bae1dSRodney W. Grimes ktrwrite(vp, kth); 169df8bae1dSRodney W. Grimes done: 170df8bae1dSRodney W. Grimes FREE(kth, M_TEMP); 171df8bae1dSRodney W. Grimes FREE(ktp, M_TEMP); 172df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 173df8bae1dSRodney W. Grimes } 174df8bae1dSRodney W. Grimes 17526f9a767SRodney W. Grimes void 176df8bae1dSRodney W. Grimes ktrpsig(vp, sig, action, mask, code) 177df8bae1dSRodney W. Grimes struct vnode *vp; 178df8bae1dSRodney W. Grimes int sig; 179df8bae1dSRodney W. Grimes sig_t action; 180df8bae1dSRodney W. Grimes int mask, code; 181df8bae1dSRodney W. Grimes { 182df8bae1dSRodney W. Grimes struct ktr_header *kth; 183df8bae1dSRodney W. Grimes struct ktr_psig kp; 184df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 185df8bae1dSRodney W. Grimes 186df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 187df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_PSIG); 188df8bae1dSRodney W. Grimes kp.signo = (char)sig; 189df8bae1dSRodney W. Grimes kp.action = action; 190df8bae1dSRodney W. Grimes kp.mask = mask; 191df8bae1dSRodney W. Grimes kp.code = code; 192df8bae1dSRodney W. Grimes kth->ktr_buf = (caddr_t)&kp; 193df8bae1dSRodney W. Grimes kth->ktr_len = sizeof (struct ktr_psig); 194df8bae1dSRodney W. Grimes 195df8bae1dSRodney W. Grimes ktrwrite(vp, kth); 196df8bae1dSRodney W. Grimes FREE(kth, M_TEMP); 197df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 198df8bae1dSRodney W. Grimes } 199df8bae1dSRodney W. Grimes 20026f9a767SRodney W. Grimes void 201df8bae1dSRodney W. Grimes ktrcsw(vp, out, user) 202df8bae1dSRodney W. Grimes struct vnode *vp; 203df8bae1dSRodney W. Grimes int out, user; 204df8bae1dSRodney W. Grimes { 205df8bae1dSRodney W. Grimes struct ktr_header *kth; 206df8bae1dSRodney W. Grimes struct ktr_csw kc; 207df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 208df8bae1dSRodney W. Grimes 209df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ACTIVE; 210df8bae1dSRodney W. Grimes kth = ktrgetheader(KTR_CSW); 211df8bae1dSRodney W. Grimes kc.out = out; 212df8bae1dSRodney W. Grimes kc.user = user; 213df8bae1dSRodney W. Grimes kth->ktr_buf = (caddr_t)&kc; 214df8bae1dSRodney W. Grimes kth->ktr_len = sizeof (struct ktr_csw); 215df8bae1dSRodney W. Grimes 216df8bae1dSRodney W. Grimes ktrwrite(vp, kth); 217df8bae1dSRodney W. Grimes FREE(kth, M_TEMP); 218df8bae1dSRodney W. Grimes p->p_traceflag &= ~KTRFAC_ACTIVE; 219df8bae1dSRodney W. Grimes } 220df8bae1dSRodney W. Grimes 221df8bae1dSRodney W. Grimes /* Interface and common routines */ 222df8bae1dSRodney W. Grimes 223df8bae1dSRodney W. Grimes /* 224df8bae1dSRodney W. Grimes * ktrace system call 225df8bae1dSRodney W. Grimes */ 226df8bae1dSRodney W. Grimes struct ktrace_args { 227df8bae1dSRodney W. Grimes char *fname; 228df8bae1dSRodney W. Grimes int ops; 229df8bae1dSRodney W. Grimes int facs; 230df8bae1dSRodney W. Grimes int pid; 231df8bae1dSRodney W. Grimes }; 232df8bae1dSRodney W. Grimes /* ARGSUSED */ 23326f9a767SRodney W. Grimes int 234df8bae1dSRodney W. Grimes ktrace(curp, uap, retval) 235df8bae1dSRodney W. Grimes struct proc *curp; 236df8bae1dSRodney W. Grimes register struct ktrace_args *uap; 237df8bae1dSRodney W. Grimes int *retval; 238df8bae1dSRodney W. Grimes { 239df8bae1dSRodney W. Grimes register struct vnode *vp = NULL; 240df8bae1dSRodney W. Grimes register struct proc *p; 241df8bae1dSRodney W. Grimes struct pgrp *pg; 242df8bae1dSRodney W. Grimes int facs = uap->facs & ~KTRFAC_ROOT; 243df8bae1dSRodney W. Grimes int ops = KTROP(uap->ops); 244df8bae1dSRodney W. Grimes int descend = uap->ops & KTRFLAG_DESCEND; 245df8bae1dSRodney W. Grimes int ret = 0; 246df8bae1dSRodney W. Grimes int error = 0; 247df8bae1dSRodney W. Grimes struct nameidata nd; 248df8bae1dSRodney W. Grimes 249df8bae1dSRodney W. Grimes curp->p_traceflag |= KTRFAC_ACTIVE; 250df8bae1dSRodney W. Grimes if (ops != KTROP_CLEAR) { 251df8bae1dSRodney W. Grimes /* 252df8bae1dSRodney W. Grimes * an operation which requires a file argument. 253df8bae1dSRodney W. Grimes */ 254df8bae1dSRodney W. Grimes NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, curp); 255df8bae1dSRodney W. Grimes if (error = vn_open(&nd, FREAD|FWRITE, 0)) { 256df8bae1dSRodney W. Grimes curp->p_traceflag &= ~KTRFAC_ACTIVE; 257df8bae1dSRodney W. Grimes return (error); 258df8bae1dSRodney W. Grimes } 259df8bae1dSRodney W. Grimes vp = nd.ni_vp; 260df8bae1dSRodney W. Grimes VOP_UNLOCK(vp); 261df8bae1dSRodney W. Grimes if (vp->v_type != VREG) { 262df8bae1dSRodney W. Grimes (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp); 263df8bae1dSRodney W. Grimes curp->p_traceflag &= ~KTRFAC_ACTIVE; 264df8bae1dSRodney W. Grimes return (EACCES); 265df8bae1dSRodney W. Grimes } 266df8bae1dSRodney W. Grimes } 267df8bae1dSRodney W. Grimes /* 268df8bae1dSRodney W. Grimes * Clear all uses of the tracefile 269df8bae1dSRodney W. Grimes */ 270df8bae1dSRodney W. Grimes if (ops == KTROP_CLEARFILE) { 271df8bae1dSRodney W. Grimes for (p = (struct proc *)allproc; p != NULL; p = p->p_next) { 272df8bae1dSRodney W. Grimes if (p->p_tracep == vp) { 273df8bae1dSRodney W. Grimes if (ktrcanset(curp, p)) { 274df8bae1dSRodney W. Grimes p->p_tracep = NULL; 275df8bae1dSRodney W. Grimes p->p_traceflag = 0; 276df8bae1dSRodney W. Grimes (void) vn_close(vp, FREAD|FWRITE, 277df8bae1dSRodney W. Grimes p->p_ucred, p); 278df8bae1dSRodney W. Grimes } else 279df8bae1dSRodney W. Grimes error = EPERM; 280df8bae1dSRodney W. Grimes } 281df8bae1dSRodney W. Grimes } 282df8bae1dSRodney W. Grimes goto done; 283df8bae1dSRodney W. Grimes } 284df8bae1dSRodney W. Grimes /* 285df8bae1dSRodney W. Grimes * need something to (un)trace (XXX - why is this here?) 286df8bae1dSRodney W. Grimes */ 287df8bae1dSRodney W. Grimes if (!facs) { 288df8bae1dSRodney W. Grimes error = EINVAL; 289df8bae1dSRodney W. Grimes goto done; 290df8bae1dSRodney W. Grimes } 291df8bae1dSRodney W. Grimes /* 292df8bae1dSRodney W. Grimes * do it 293df8bae1dSRodney W. Grimes */ 294df8bae1dSRodney W. Grimes if (uap->pid < 0) { 295df8bae1dSRodney W. Grimes /* 296df8bae1dSRodney W. Grimes * by process group 297df8bae1dSRodney W. Grimes */ 298df8bae1dSRodney W. Grimes pg = pgfind(-uap->pid); 299df8bae1dSRodney W. Grimes if (pg == NULL) { 300df8bae1dSRodney W. Grimes error = ESRCH; 301df8bae1dSRodney W. Grimes goto done; 302df8bae1dSRodney W. Grimes } 303df8bae1dSRodney W. Grimes for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) 304df8bae1dSRodney W. Grimes if (descend) 305df8bae1dSRodney W. Grimes ret |= ktrsetchildren(curp, p, ops, facs, vp); 306df8bae1dSRodney W. Grimes else 307df8bae1dSRodney W. Grimes ret |= ktrops(curp, p, ops, facs, vp); 308df8bae1dSRodney W. Grimes 309df8bae1dSRodney W. Grimes } else { 310df8bae1dSRodney W. Grimes /* 311df8bae1dSRodney W. Grimes * by pid 312df8bae1dSRodney W. Grimes */ 313df8bae1dSRodney W. Grimes p = pfind(uap->pid); 314df8bae1dSRodney W. Grimes if (p == NULL) { 315df8bae1dSRodney W. Grimes error = ESRCH; 316df8bae1dSRodney W. Grimes goto done; 317df8bae1dSRodney W. Grimes } 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 } 323df8bae1dSRodney W. Grimes if (!ret) 324df8bae1dSRodney W. Grimes error = EPERM; 325df8bae1dSRodney W. Grimes done: 326df8bae1dSRodney W. Grimes if (vp != NULL) 327df8bae1dSRodney W. Grimes (void) vn_close(vp, FWRITE, curp->p_ucred, curp); 328df8bae1dSRodney W. Grimes curp->p_traceflag &= ~KTRFAC_ACTIVE; 329df8bae1dSRodney W. Grimes return (error); 330df8bae1dSRodney W. Grimes } 331df8bae1dSRodney W. Grimes 332df8bae1dSRodney W. Grimes int 333df8bae1dSRodney W. Grimes ktrops(curp, p, ops, facs, vp) 334df8bae1dSRodney W. Grimes struct proc *p, *curp; 335df8bae1dSRodney W. Grimes int ops, facs; 336df8bae1dSRodney W. Grimes struct vnode *vp; 337df8bae1dSRodney W. Grimes { 338df8bae1dSRodney W. Grimes 339df8bae1dSRodney W. Grimes if (!ktrcanset(curp, p)) 340df8bae1dSRodney W. Grimes return (0); 341df8bae1dSRodney W. Grimes if (ops == KTROP_SET) { 342df8bae1dSRodney W. Grimes if (p->p_tracep != vp) { 343df8bae1dSRodney W. Grimes /* 344df8bae1dSRodney W. Grimes * if trace file already in use, relinquish 345df8bae1dSRodney W. Grimes */ 346df8bae1dSRodney W. Grimes if (p->p_tracep != NULL) 347df8bae1dSRodney W. Grimes vrele(p->p_tracep); 348df8bae1dSRodney W. Grimes VREF(vp); 349df8bae1dSRodney W. Grimes p->p_tracep = vp; 350df8bae1dSRodney W. Grimes } 351df8bae1dSRodney W. Grimes p->p_traceflag |= facs; 352df8bae1dSRodney W. Grimes if (curp->p_ucred->cr_uid == 0) 353df8bae1dSRodney W. Grimes p->p_traceflag |= KTRFAC_ROOT; 354df8bae1dSRodney W. Grimes } else { 355df8bae1dSRodney W. Grimes /* KTROP_CLEAR */ 356df8bae1dSRodney W. Grimes if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { 357df8bae1dSRodney W. Grimes /* no more tracing */ 358df8bae1dSRodney W. Grimes p->p_traceflag = 0; 359df8bae1dSRodney W. Grimes if (p->p_tracep != NULL) { 360df8bae1dSRodney W. Grimes vrele(p->p_tracep); 361df8bae1dSRodney W. Grimes p->p_tracep = NULL; 362df8bae1dSRodney W. Grimes } 363df8bae1dSRodney W. Grimes } 364df8bae1dSRodney W. Grimes } 365df8bae1dSRodney W. Grimes 366df8bae1dSRodney W. Grimes return (1); 367df8bae1dSRodney W. Grimes } 368df8bae1dSRodney W. Grimes 36926f9a767SRodney W. Grimes int 370df8bae1dSRodney W. Grimes ktrsetchildren(curp, top, ops, facs, vp) 371df8bae1dSRodney W. Grimes struct proc *curp, *top; 372df8bae1dSRodney W. Grimes int ops, facs; 373df8bae1dSRodney W. Grimes struct vnode *vp; 374df8bae1dSRodney W. Grimes { 375df8bae1dSRodney W. Grimes register struct proc *p; 376df8bae1dSRodney W. Grimes register int ret = 0; 377df8bae1dSRodney W. Grimes 378df8bae1dSRodney W. Grimes p = top; 379df8bae1dSRodney W. Grimes for (;;) { 380df8bae1dSRodney W. Grimes ret |= ktrops(curp, p, ops, facs, vp); 381df8bae1dSRodney W. Grimes /* 382df8bae1dSRodney W. Grimes * If this process has children, descend to them next, 383df8bae1dSRodney W. Grimes * otherwise do any siblings, and if done with this level, 384df8bae1dSRodney W. Grimes * follow back up the tree (but not past top). 385df8bae1dSRodney W. Grimes */ 386df8bae1dSRodney W. Grimes if (p->p_cptr) 387df8bae1dSRodney W. Grimes p = p->p_cptr; 388df8bae1dSRodney W. Grimes else if (p == top) 389df8bae1dSRodney W. Grimes return (ret); 390df8bae1dSRodney W. Grimes else if (p->p_osptr) 391df8bae1dSRodney W. Grimes p = p->p_osptr; 392df8bae1dSRodney W. Grimes else for (;;) { 393df8bae1dSRodney W. Grimes p = p->p_pptr; 394df8bae1dSRodney W. Grimes if (p == top) 395df8bae1dSRodney W. Grimes return (ret); 396df8bae1dSRodney W. Grimes if (p->p_osptr) { 397df8bae1dSRodney W. Grimes p = p->p_osptr; 398df8bae1dSRodney W. Grimes break; 399df8bae1dSRodney W. Grimes } 400df8bae1dSRodney W. Grimes } 401df8bae1dSRodney W. Grimes } 402df8bae1dSRodney W. Grimes /*NOTREACHED*/ 403df8bae1dSRodney W. Grimes } 404df8bae1dSRodney W. Grimes 40526f9a767SRodney W. Grimes void 406df8bae1dSRodney W. Grimes ktrwrite(vp, kth) 407df8bae1dSRodney W. Grimes struct vnode *vp; 408df8bae1dSRodney W. Grimes register struct ktr_header *kth; 409df8bae1dSRodney W. Grimes { 410df8bae1dSRodney W. Grimes struct uio auio; 411df8bae1dSRodney W. Grimes struct iovec aiov[2]; 412df8bae1dSRodney W. Grimes register struct proc *p = curproc; /* XXX */ 413df8bae1dSRodney W. Grimes int error; 414df8bae1dSRodney W. Grimes 415df8bae1dSRodney W. Grimes if (vp == NULL) 416df8bae1dSRodney W. Grimes return; 417df8bae1dSRodney W. Grimes auio.uio_iov = &aiov[0]; 418df8bae1dSRodney W. Grimes auio.uio_offset = 0; 419df8bae1dSRodney W. Grimes auio.uio_segflg = UIO_SYSSPACE; 420df8bae1dSRodney W. Grimes auio.uio_rw = UIO_WRITE; 421df8bae1dSRodney W. Grimes aiov[0].iov_base = (caddr_t)kth; 422df8bae1dSRodney W. Grimes aiov[0].iov_len = sizeof(struct ktr_header); 423df8bae1dSRodney W. Grimes auio.uio_resid = sizeof(struct ktr_header); 424df8bae1dSRodney W. Grimes auio.uio_iovcnt = 1; 425df8bae1dSRodney W. Grimes auio.uio_procp = (struct proc *)0; 426df8bae1dSRodney W. Grimes if (kth->ktr_len > 0) { 427df8bae1dSRodney W. Grimes auio.uio_iovcnt++; 428df8bae1dSRodney W. Grimes aiov[1].iov_base = kth->ktr_buf; 429df8bae1dSRodney W. Grimes aiov[1].iov_len = kth->ktr_len; 430df8bae1dSRodney W. Grimes auio.uio_resid += kth->ktr_len; 431df8bae1dSRodney W. Grimes } 432df8bae1dSRodney W. Grimes VOP_LOCK(vp); 433df8bae1dSRodney W. Grimes error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred); 434df8bae1dSRodney W. Grimes VOP_UNLOCK(vp); 435df8bae1dSRodney W. Grimes if (!error) 436df8bae1dSRodney W. Grimes return; 437df8bae1dSRodney W. Grimes /* 438df8bae1dSRodney W. Grimes * If error encountered, give up tracing on this vnode. 439df8bae1dSRodney W. Grimes */ 440df8bae1dSRodney W. Grimes log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", 441df8bae1dSRodney W. Grimes error); 442df8bae1dSRodney W. Grimes for (p = (struct proc *)allproc; p != NULL; p = p->p_next) { 443df8bae1dSRodney W. Grimes if (p->p_tracep == vp) { 444df8bae1dSRodney W. Grimes p->p_tracep = NULL; 445df8bae1dSRodney W. Grimes p->p_traceflag = 0; 446df8bae1dSRodney W. Grimes vrele(vp); 447df8bae1dSRodney W. Grimes } 448df8bae1dSRodney W. Grimes } 449df8bae1dSRodney W. Grimes } 450df8bae1dSRodney W. Grimes 451df8bae1dSRodney W. Grimes /* 452df8bae1dSRodney W. Grimes * Return true if caller has permission to set the ktracing state 453df8bae1dSRodney W. Grimes * of target. Essentially, the target can't possess any 454df8bae1dSRodney W. Grimes * more permissions than the caller. KTRFAC_ROOT signifies that 455df8bae1dSRodney W. Grimes * root previously set the tracing status on the target process, and 456df8bae1dSRodney W. Grimes * so, only root may further change it. 457df8bae1dSRodney W. Grimes * 458df8bae1dSRodney W. Grimes * TODO: check groups. use caller effective gid. 459df8bae1dSRodney W. Grimes */ 46026f9a767SRodney W. Grimes int 461df8bae1dSRodney W. Grimes ktrcanset(callp, targetp) 462df8bae1dSRodney W. Grimes struct proc *callp, *targetp; 463df8bae1dSRodney W. Grimes { 464df8bae1dSRodney W. Grimes register struct pcred *caller = callp->p_cred; 465df8bae1dSRodney W. Grimes register struct pcred *target = targetp->p_cred; 466df8bae1dSRodney W. Grimes 467df8bae1dSRodney W. Grimes if ((caller->pc_ucred->cr_uid == target->p_ruid && 468df8bae1dSRodney W. Grimes target->p_ruid == target->p_svuid && 469df8bae1dSRodney W. Grimes caller->p_rgid == target->p_rgid && /* XXX */ 470df8bae1dSRodney W. Grimes target->p_rgid == target->p_svgid && 471df8bae1dSRodney W. Grimes (targetp->p_traceflag & KTRFAC_ROOT) == 0) || 472df8bae1dSRodney W. Grimes caller->pc_ucred->cr_uid == 0) 473df8bae1dSRodney W. Grimes return (1); 474df8bae1dSRodney W. Grimes 475df8bae1dSRodney W. Grimes return (0); 476df8bae1dSRodney W. Grimes } 477df8bae1dSRodney W. Grimes 478df8bae1dSRodney W. Grimes #endif 479