1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)kern_ktrace.c 1.5 (Berkeley) 07/05/89 18 */ 19 20 #ifdef KTRACE 21 22 #include "param.h" 23 #include "user.h" 24 #include "proc.h" 25 #include "file.h" 26 #include "vnode.h" 27 #include "ktrace.h" 28 #include "malloc.h" 29 30 #include "syscalls.c" 31 32 extern int nsysent; 33 extern char *syscallnames[]; 34 35 int ktrace_nocheck = 1; 36 37 struct ktr_header * 38 ktrgetheader(type) 39 { 40 register struct ktr_header *kth; 41 42 MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header), 43 M_TEMP, M_WAITOK); 44 kth->ktr_type = type; 45 microtime(&kth->ktr_time); 46 kth->ktr_pid = u.u_procp->p_pid; 47 bcopy(u.u_comm, kth->ktr_comm, MAXCOMLEN); 48 return (kth); 49 } 50 51 ktrsyscall(vp, code, narg) 52 struct vnode *vp; 53 { 54 struct ktr_header *kth = ktrgetheader(KTR_SYSCALL); 55 struct ktr_syscall *ktp; 56 register len = sizeof(struct ktr_syscall) + (narg * sizeof(int)); 57 int *argp, i; 58 59 if (kth == NULL) 60 return; 61 MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); 62 ktp->ktr_code = code; 63 ktp->ktr_narg = narg; 64 argp = (int *)((char *)ktp + sizeof(struct ktr_syscall)); 65 for (i = 0; i < narg; i++) 66 *argp++ = u.u_arg[i]; 67 kth->ktr_buf = (caddr_t)ktp; 68 kth->ktr_len = len; 69 ktrwrite(vp, kth); 70 FREE(ktp, M_TEMP); 71 FREE(kth, M_TEMP); 72 } 73 74 ktrsysret(vp, code) 75 struct vnode *vp; 76 { 77 struct ktr_header *kth = ktrgetheader(KTR_SYSRET); 78 struct ktr_sysret *ktp; 79 80 if (kth == NULL) 81 return; 82 MALLOC(ktp, struct ktr_sysret *, sizeof(struct ktr_sysret), 83 M_TEMP , M_WAITOK); 84 ktp->ktr_code = code; 85 ktp->ktr_eosys = u.u_eosys; 86 ktp->ktr_error = u.u_error; 87 ktp->ktr_retval = u.u_r.r_val1; /* what about val2 ? */ 88 89 kth->ktr_buf = (caddr_t)ktp; 90 kth->ktr_len = sizeof(struct ktr_sysret); 91 92 ktrwrite(vp, kth); 93 FREE(ktp, M_TEMP); 94 FREE(kth, M_TEMP); 95 } 96 97 ktrnamei(vp, path) 98 struct vnode *vp; 99 char *path; 100 { 101 struct ktr_header *kth = ktrgetheader(KTR_NAMEI); 102 103 if (kth == NULL) 104 return; 105 kth->ktr_len = strlen(path); 106 kth->ktr_buf = path; 107 108 ktrwrite(vp, kth); 109 FREE(kth, M_TEMP); 110 } 111 112 ktrgenio(vp, fd, rw, iov, len) 113 struct vnode *vp; 114 enum uio_rw rw; 115 register struct iovec *iov; 116 { 117 struct ktr_header *kth = ktrgetheader(KTR_GENIO); 118 register struct ktr_genio *ktp; 119 register caddr_t cp; 120 register int resid = len, cnt; 121 122 if (kth == NULL || u.u_error) 123 return; 124 MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, 125 M_TEMP, M_WAITOK); 126 ktp->ktr_fd = fd; 127 ktp->ktr_rw = rw; 128 cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); 129 while (resid > 0) { 130 if ((cnt = iov->iov_len) > resid) 131 cnt = resid; 132 if (copyin(iov->iov_base, cp, cnt)) 133 goto done; 134 cp += cnt; 135 resid -= cnt; 136 iov++; 137 } 138 kth->ktr_buf = (caddr_t)ktp; 139 kth->ktr_len = sizeof (struct ktr_genio) + len; 140 141 ktrwrite(vp, kth); 142 done: 143 FREE(kth, M_TEMP); 144 FREE(ktp, M_TEMP); 145 } 146 147 /* 148 * ktrace system call 149 */ 150 ktrace() 151 { 152 register struct a { 153 char *fname; 154 int ops; 155 int facs; 156 int pid; 157 } *uap = (struct a *)u.u_ap; 158 register struct vnode *vp = NULL; 159 register struct nameidata *ndp = &u.u_nd; 160 register struct proc *p; 161 struct pgrp *pg; 162 register int ops = uap->ops&0x3; 163 register int facs = uap->facs; 164 register int ret = 0; 165 166 /* 167 * Until security implications are thought through, 168 * limit tracing to root (unless ktrace_nocheck is set). 169 */ 170 if (!ktrace_nocheck && (u.u_error = suser(u.u_cred, &u.u_acflag))) 171 return; 172 if (ops != KTROP_CLEAR) { 173 /* 174 * an operation which requires a file argument. 175 */ 176 ndp->ni_segflg = UIO_USERSPACE; 177 ndp->ni_dirp = uap->fname; 178 if (u.u_error = vn_open(ndp, FREAD|FWRITE, 0)) 179 return; 180 vp = ndp->ni_vp; 181 if (vp->v_type != VREG) { 182 u.u_error = EACCES; 183 vrele(vp); 184 return; 185 } 186 } 187 /* 188 * Clear all uses of the tracefile 189 */ 190 if (ops == KTROP_CLEARFILE) { 191 for (p = allproc; p != NULL; p = p->p_nxt) { 192 if (p->p_tracep == vp) { 193 p->p_flag &= ~SKTR; 194 p->p_tracep = NULL; 195 p->p_traceflag = 0; 196 vrele(vp); 197 } 198 } 199 goto done; 200 } 201 202 /* 203 * need something to (un)trace 204 */ 205 if (!facs) { 206 u.u_error = EINVAL; 207 goto done; 208 } 209 210 if (uap->pid < 0) { 211 pg = pgfind(-uap->pid); 212 if (pg == NULL) { 213 u.u_error = ESRCH; 214 goto done; 215 } 216 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) 217 if (uap->ops&KTROP_INHERITFLAG) 218 ret |= ktrsetchildren(p, ops, facs, vp); 219 else 220 ret |= ktrops(p, ops, facs, vp); 221 222 } else { 223 p = pfind(uap->pid); 224 if (p == NULL) { 225 u.u_error = ESRCH; 226 goto done; 227 } 228 if (uap->ops&KTROP_INHERITFLAG) 229 ret |= ktrsetchildren(p, ops, facs, vp); 230 else 231 ret |= ktrops(p, ops, facs, vp); 232 } 233 if (!ret) 234 u.u_error = EPERM; 235 done: 236 if (vp != NULL) 237 vrele(vp); 238 } 239 240 ktrops(p, ops, facs, vp) 241 struct proc *p; 242 struct vnode *vp; 243 { 244 245 if (u.u_uid && u.u_uid != p->p_uid) 246 return 0; 247 if (ops == KTROP_SET) { 248 if (p->p_tracep != vp) { 249 /* 250 * if trace file already in use, relinquish 251 */ 252 if (p->p_tracep != NULL) 253 vrele(p->p_tracep); 254 VREF(vp); 255 p->p_tracep = vp; 256 } 257 p->p_traceflag |= facs; 258 } else { 259 /* KTROP_CLEAR */ 260 if ((p->p_traceflag &= ~facs) == 0) { 261 if (p->p_tracep != NULL) { 262 vrele(p->p_tracep); 263 p->p_tracep = NULL; 264 } 265 p->p_flag &= ~SKTR; 266 } 267 } 268 269 return 1; 270 } 271 272 ktrsetchildren(top, ops, facs, vp) 273 struct proc *top; 274 struct vnode *vp; 275 { 276 register struct proc *p; 277 register int ndx; 278 register int ret = 0; 279 280 p = top; 281 for (;;) { 282 if ((ret |= ktrops(p, ops, facs, vp)) && ops == KTROP_SET) 283 p->p_flag |= SKTR; 284 /* 285 * If this process has children, descend to them next, 286 * otherwise do any siblings, and if done with this level, 287 * follow back up the tree (but not past top). 288 */ 289 if (p->p_cptr) 290 p = p->p_cptr; 291 else if (p == top) 292 return ret; 293 else if (p->p_osptr) 294 p = p->p_osptr; 295 else for (;;) { 296 p = p->p_pptr; 297 if (p == top) 298 return ret; 299 if (p->p_osptr) { 300 p = p->p_osptr; 301 break; 302 } 303 } 304 } 305 /*NOTREACHED*/ 306 } 307 308 ktrwrite(vp, kth) 309 struct vnode *vp; 310 register struct ktr_header *kth; 311 { 312 struct uio auio; 313 struct iovec aiov[2]; 314 int offset, error; 315 316 if (vp == NULL) 317 return; 318 auio.uio_iov = &aiov[0]; 319 auio.uio_offset = 0; 320 auio.uio_segflg = UIO_SYSSPACE; 321 auio.uio_rw = UIO_WRITE; 322 aiov[0].iov_base = (caddr_t)kth; 323 aiov[0].iov_len = sizeof(struct ktr_header); 324 auio.uio_resid = sizeof(struct ktr_header); 325 auio.uio_iovcnt = 1; 326 if (kth->ktr_len > 0) { 327 auio.uio_iovcnt++; 328 aiov[1].iov_base = kth->ktr_buf; 329 aiov[1].iov_len = kth->ktr_len; 330 auio.uio_resid += kth->ktr_len; 331 } 332 error = VOP_WRITE(vp, &auio, &offset, IO_UNIT|IO_APPEND, u.u_cred); 333 } 334 #endif 335