136359Smarc /* 236359Smarc * Copyright (c) 1989 The Regents of the University of California. 336359Smarc * All rights reserved. 436359Smarc * 536359Smarc * Redistribution and use in source and binary forms are permitted 636359Smarc * provided that the above copyright notice and this paragraph are 736359Smarc * duplicated in all such forms and that any documentation, 836359Smarc * advertising materials, and other materials related to such 936359Smarc * distribution and use acknowledge that the software was developed 1036359Smarc * by the University of California, Berkeley. The name of the 1136359Smarc * University may not be used to endorse or promote products derived 1236359Smarc * from this software without specific prior written permission. 1336359Smarc * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1436359Smarc * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1536359Smarc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1636359Smarc * 17*37593Smarc * @(#)kern_ktrace.c 1.3 (Berkeley) 05/01/89 1836359Smarc */ 1936359Smarc 2036359Smarc #ifdef KTRACE 2136359Smarc 2236359Smarc #include "param.h" 2336359Smarc #include "systm.h" 2436359Smarc #include "dir.h" 2536359Smarc #include "user.h" 2636359Smarc #include "assym.s" 2736359Smarc #include "proc.h" 2836359Smarc #include "seg.h" 2936359Smarc #include "acct.h" 3036359Smarc #include "fs.h" 3136359Smarc #include "inode.h" 3236359Smarc #include "syslog.h" 3336359Smarc #include "kernel.h" 3436359Smarc #include "ktrace.h" 3536359Smarc #include "malloc.h" 3636359Smarc 37*37593Smarc #include "syscalls.c" 3836359Smarc 3936359Smarc extern int nsysent; 4036359Smarc extern char *syscallnames[]; 4136359Smarc 42*37593Smarc int ktrace_nocheck = 1; 43*37593Smarc 4436359Smarc struct ktr_header * 4536359Smarc ktrgetheader(type) 4636359Smarc { 4736359Smarc register struct ktr_header *kth; 4836359Smarc 4936359Smarc MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 5036359Smarc M_TEMP, M_WAITOK); 5136359Smarc if (kth == NULL) 5236359Smarc return (NULL); 5336359Smarc kth->ktr_type = type; 54*37593Smarc microtime(&kth->ktr_time); 5536359Smarc kth->ktr_pid = u.u_procp->p_pid; 5636359Smarc bcopy(u.u_comm, kth->ktr_comm, MAXCOMLEN); 5736359Smarc 58*37593Smarc if (kth == NULL) 59*37593Smarc printf("ktrgetheader: can't malloc header for %d\n", type); 6036359Smarc return (kth); 6136359Smarc } 6236359Smarc 6336359Smarc ktrsyscall(ip, code, narg) 6436359Smarc struct inode *ip; 6536359Smarc { 6636359Smarc struct ktr_header *kth = ktrgetheader(KTR_SYSCALL); 6736359Smarc struct ktr_syscall *ktp; 6836359Smarc register len = sizeof(struct ktr_syscall) + (narg * sizeof(int)); 6936359Smarc int *argp, i; 7036359Smarc 71*37593Smarc if (kth == NULL) 7236359Smarc return; 7336359Smarc MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); 7436359Smarc if (ktp == NULL) { 7536359Smarc printf("lost syscall trace - no buffer\n"); /* DEBUG */ 7636359Smarc FREE(kth, M_TEMP); 7736359Smarc return; 7836359Smarc } 7936359Smarc ktp->ktr_code = code; 8036359Smarc ktp->ktr_narg = narg; 8136359Smarc argp = (int *)((char *)ktp + sizeof(struct ktr_syscall)); 8236359Smarc for (i = 0; i < narg; i++) 8336359Smarc *argp++ = u.u_arg[i]; 8436359Smarc kth->ktr_buf = (caddr_t)ktp; 8536359Smarc kth->ktr_len = len; 8636359Smarc ktrwrite(ip, kth); 8736359Smarc FREE(ktp, M_TEMP); 8836359Smarc FREE(kth, M_TEMP); 8936359Smarc } 9036359Smarc 9136359Smarc ktrsysret(ip, code) 9236359Smarc struct inode *ip; 9336359Smarc { 9436359Smarc struct ktr_header *kth = ktrgetheader(KTR_SYSRET); 9536359Smarc struct ktr_sysret *ktp; 9636359Smarc 97*37593Smarc if (kth == NULL) 9836359Smarc return; 9936359Smarc MALLOC(ktp, struct ktr_sysret *, sizeof(struct ktr_sysret), 10036359Smarc M_TEMP , M_WAITOK); 10136359Smarc if (ktp == NULL) { 10236359Smarc printf("lost syscall ret - no buffer\n"); /* DEBUG */ 10336359Smarc FREE(kth, M_TEMP); 10436359Smarc return; 10536359Smarc } 10636359Smarc ktp->ktr_code = code; 10736359Smarc ktp->ktr_eosys = u.u_eosys; 10836359Smarc ktp->ktr_error = u.u_error; 10936359Smarc ktp->ktr_retval = u.u_r.r_val1; /* what about val2 ? */ 11036359Smarc 11136359Smarc kth->ktr_buf = (caddr_t)ktp; 11236359Smarc kth->ktr_len = sizeof(struct ktr_sysret); 11336359Smarc 11436359Smarc ktrwrite(ip, kth); 11536359Smarc FREE(ktp, M_TEMP); 11636359Smarc FREE(kth, M_TEMP); 11736359Smarc } 11836359Smarc 11936359Smarc ktrnamei(ip, path) 12036359Smarc struct inode *ip; 12136359Smarc char *path; 12236359Smarc { 12336359Smarc struct ktr_header *kth = ktrgetheader(KTR_NAMEI); 12436359Smarc 125*37593Smarc if (kth == NULL) 12636359Smarc return; 12736359Smarc kth->ktr_len = strlen(path); 12836359Smarc kth->ktr_buf = path; 12936359Smarc 13036359Smarc ktrwrite(ip, kth); 13136359Smarc FREE(kth, M_TEMP); 13236359Smarc } 13336359Smarc 134*37593Smarc ktrgenio(ip, fd, rw, iov, len) 135*37593Smarc struct inode *ip; 136*37593Smarc enum uio_rw rw; 137*37593Smarc register struct iovec *iov; 138*37593Smarc { 139*37593Smarc struct ktr_header *kth = ktrgetheader(KTR_GENIO); 140*37593Smarc register struct ktr_genio *ktp; 141*37593Smarc register caddr_t cp; 142*37593Smarc register int resid = len, cnt; 143*37593Smarc 144*37593Smarc if (kth == NULL || u.u_error) 145*37593Smarc return; 146*37593Smarc MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, 147*37593Smarc M_TEMP, M_WAITOK); 148*37593Smarc if (ktp == NULL) { 149*37593Smarc printf("lost ktr_genio data buffer\n"); 150*37593Smarc FREE(kth, M_TEMP); 151*37593Smarc return; 152*37593Smarc } 153*37593Smarc ktp->ktr_fd = fd; 154*37593Smarc ktp->ktr_rw = rw; 155*37593Smarc cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); 156*37593Smarc while (resid > 0) { 157*37593Smarc if ((cnt = iov->iov_len) > resid) 158*37593Smarc cnt = resid; 159*37593Smarc if (copyin(iov->iov_base, cp, cnt)) 160*37593Smarc goto done; 161*37593Smarc cp += cnt; 162*37593Smarc resid -= cnt; 163*37593Smarc iov++; 164*37593Smarc } 165*37593Smarc kth->ktr_buf = (caddr_t)ktp; 166*37593Smarc kth->ktr_len = sizeof (struct ktr_genio) + len; 167*37593Smarc 168*37593Smarc ktrwrite(ip, kth); 169*37593Smarc done: 170*37593Smarc FREE(kth, M_TEMP); 171*37593Smarc FREE(ktp, M_TEMP); 172*37593Smarc } 173*37593Smarc 17436359Smarc /* 17536359Smarc * ktrace system call 17636359Smarc */ 17736359Smarc ktrace() 17836359Smarc { 17936359Smarc register struct inode *ip = NULL; 18036359Smarc register struct a { 18136359Smarc char *fname; 18236359Smarc int ops; 18336359Smarc int facs; 184*37593Smarc int pid; 18536359Smarc } *uap = (struct a *)u.u_ap; 18636359Smarc register struct nameidata *ndp = &u.u_nd; 18736359Smarc register struct proc *p; 18836359Smarc struct pgrp *pg; 18936359Smarc register int ops = uap->ops&0x3; 19036359Smarc register int facs = uap->facs; 191*37593Smarc register int ret = 0; 19236359Smarc 19336359Smarc /* 19436359Smarc * Until security implications are thought through, 195*37593Smarc * limit tracing to root (unless ktrace_nocheck is set). 19636359Smarc */ 19737555Smckusick if (!ktrace_nocheck && (u.u_error = suser(u.u_cred, &u.u_acflag))) 19836359Smarc return; 19936359Smarc if (ops != KTROP_CLEAR) { 20036359Smarc /* 20136359Smarc * an operation which requires a file argument. 20236359Smarc */ 20336359Smarc ndp->ni_nameiop = LOOKUP | FOLLOW; 20436359Smarc ndp->ni_segflg = UIO_USERSPACE; 20536359Smarc ndp->ni_dirp = uap->fname; 20636359Smarc ip = namei(ndp); 20736359Smarc if (ip == NULL) 20836359Smarc return; 209*37593Smarc if (access(ip, IWRITE)) { 210*37593Smarc iput(ip); 211*37593Smarc return; 212*37593Smarc } 21336359Smarc if ((ip->i_mode&IFMT) != IFREG) { 21436359Smarc u.u_error = EACCES; 21536359Smarc iput(ip); 21636359Smarc return; 21736359Smarc } 21836359Smarc if (ip->i_fs->fs_ronly) { 21936359Smarc u.u_error = EROFS; 22036359Smarc iput(ip); 22136359Smarc return; 22236359Smarc } 22336359Smarc iunlock(ip); 22436359Smarc } 22536359Smarc /* 22636359Smarc * Clear all uses of the tracefile 22736359Smarc */ 22836359Smarc if (ops == KTROP_CLEARFILE) { 22936359Smarc for (p = allproc; p != NULL; p = p->p_nxt) { 23036359Smarc if (p->p_tracep == ip) { 23136359Smarc p->p_flag &= ~SKTR; 23236359Smarc p->p_tracep = NULL; 23336359Smarc p->p_traceflag = 0; 23436359Smarc irele(ip); 23536359Smarc } 23636359Smarc } 23736359Smarc goto done; 23836359Smarc } 23936359Smarc 24036359Smarc /* 24136359Smarc * need something to (un)trace 24236359Smarc */ 24336359Smarc if (!facs) { 24436359Smarc u.u_error = EINVAL; 24536359Smarc goto done; 24636359Smarc } 24736359Smarc 24836359Smarc if (uap->pid < 0) { 24936359Smarc pg = pgfind(-uap->pid); 25036359Smarc if (pg == NULL) { 25136359Smarc u.u_error = ESRCH; 25236359Smarc goto done; 25336359Smarc } 25436359Smarc for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) 25536359Smarc if (uap->ops&KTROP_INHERITFLAG) 256*37593Smarc ret |= ktrsetchildren(p, ops, facs, ip); 25736359Smarc else 258*37593Smarc ret |= ktrops(p, ops, facs, ip); 25936359Smarc 26036359Smarc } else { 26136359Smarc p = pfind(uap->pid); 26236359Smarc if (p == NULL) { 26336359Smarc u.u_error = ESRCH; 26436359Smarc goto done; 26536359Smarc } 26636359Smarc if (uap->ops&KTROP_INHERITFLAG) 267*37593Smarc ret |= ktrsetchildren(p, ops, facs, ip); 26836359Smarc else 269*37593Smarc ret |= ktrops(p, ops, facs, ip); 27036359Smarc } 271*37593Smarc if (!ret) 272*37593Smarc u.u_error = EPERM; 27336359Smarc done: 27436359Smarc if (ip != NULL) 27536359Smarc irele(ip); 27636359Smarc } 27736359Smarc 27836359Smarc ktrops(p, ops, facs, ip) 27936359Smarc struct proc *p; 28036359Smarc struct inode *ip; 28136359Smarc { 282*37593Smarc 283*37593Smarc if (u.u_uid && u.u_uid != p->p_uid) 284*37593Smarc return 0; 28536359Smarc if (ops == KTROP_SET) { 28636359Smarc if (p->p_tracep != ip) { 28736359Smarc /* 28836359Smarc * if trace file already in use, relinquish 28936359Smarc */ 29036359Smarc if (p->p_tracep != NULL) 29136359Smarc irele(p->p_tracep); 29236359Smarc igrab(ip); 29336359Smarc p->p_tracep = ip; 29436359Smarc iunlock(ip); 29536359Smarc } 29636359Smarc p->p_traceflag |= facs; 29736359Smarc } else { 29836359Smarc /* KTROP_CLEAR */ 29936359Smarc if ((p->p_traceflag &= ~facs) == 0) { 30036359Smarc if (p->p_tracep != NULL) { 30136359Smarc irele(p->p_tracep); 30236359Smarc p->p_tracep = NULL; 30336359Smarc } 304*37593Smarc p->p_flag &= ~SKTR; 30536359Smarc } 30636359Smarc } 307*37593Smarc 308*37593Smarc return 1; 30936359Smarc } 310*37593Smarc 31136359Smarc ktrsetchildren(top, ops, facs, ip) 31236359Smarc struct proc *top; 31336359Smarc struct inode *ip; 31436359Smarc { 31536359Smarc register struct proc *p; 31636359Smarc register int ndx; 317*37593Smarc register int ret = 0; 31836359Smarc 31936359Smarc p = top; 32036359Smarc for (;;) { 321*37593Smarc if ((ret |= ktrops(p, ops, facs, ip)) && ops == KTROP_SET) 32236359Smarc p->p_flag |= SKTR; 32336359Smarc /* 32436359Smarc * If this process has children, descend to them next, 32536359Smarc * otherwise do any siblings, and if done with this level, 32636359Smarc * follow back up the tree (but not past top). 32736359Smarc */ 32836359Smarc if (p->p_cptr) 32936359Smarc p = p->p_cptr; 33036359Smarc else if (p == top) 331*37593Smarc return ret; 33236359Smarc else if (p->p_osptr) 33336359Smarc p = p->p_osptr; 33436359Smarc else for (;;) { 33536359Smarc p = p->p_pptr; 33636359Smarc if (p == top) 337*37593Smarc return ret; 33836359Smarc if (p->p_osptr) { 33936359Smarc p = p->p_osptr; 34036359Smarc break; 34136359Smarc } 34236359Smarc } 34336359Smarc } 344*37593Smarc /*NOTREACHED*/ 34536359Smarc } 34636359Smarc 34736359Smarc ktrwrite(ip, kth) 34836359Smarc register struct inode *ip; 34936359Smarc struct ktr_header *kth; 35036359Smarc { 35136359Smarc int save = u.u_error; 35236359Smarc int osize; 35336359Smarc 354*37593Smarc if (ip == NULL) 355*37593Smarc return; 35636359Smarc ilock(ip); 35736359Smarc osize = ip->i_size; 35836359Smarc u.u_error = 0; 35936359Smarc u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)kth, 36036359Smarc sizeof(struct ktr_header), ip->i_size, 1, (int *)0); 36136359Smarc if (u.u_error) { 36236359Smarc itrunc(ip, (u_long)osize); 36336359Smarc goto end; 36436359Smarc } 36536359Smarc if (kth->ktr_len > 0) { 36636359Smarc u.u_error = rdwri(UIO_WRITE, ip, kth->ktr_buf, 36736359Smarc kth->ktr_len, ip->i_size, 1, (int *)0); 36836359Smarc if (u.u_error) 36936359Smarc itrunc(ip, (u_long)osize); 37036359Smarc } 37136359Smarc end: 37236359Smarc u.u_error = save; 37336359Smarc iunlock(ip); 37436359Smarc } 37536359Smarc 37636359Smarc #endif 377