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 7.3 (Berkeley) 04/05/90 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_procp->p_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 ktp.ktr_code = code; 83 ktp.ktr_eosys = u.u_eosys; 84 ktp.ktr_error = u.u_error; 85 ktp.ktr_retval = u.u_r.r_val1; /* what about val2 ? */ 86 87 kth->ktr_buf = (caddr_t)&ktp; 88 kth->ktr_len = sizeof(struct ktr_sysret); 89 90 ktrwrite(vp, kth); 91 FREE(kth, M_TEMP); 92 } 93 94 ktrnamei(vp, path) 95 struct vnode *vp; 96 char *path; 97 { 98 struct ktr_header *kth = ktrgetheader(KTR_NAMEI); 99 100 if (kth == NULL) 101 return; 102 kth->ktr_len = strlen(path); 103 kth->ktr_buf = path; 104 105 ktrwrite(vp, kth); 106 FREE(kth, M_TEMP); 107 } 108 109 ktrgenio(vp, fd, rw, iov, len) 110 struct vnode *vp; 111 enum uio_rw rw; 112 register struct iovec *iov; 113 { 114 struct ktr_header *kth = ktrgetheader(KTR_GENIO); 115 register struct ktr_genio *ktp; 116 register caddr_t cp; 117 register int resid = len, cnt; 118 119 if (kth == NULL || u.u_error) 120 return; 121 MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, 122 M_TEMP, M_WAITOK); 123 ktp->ktr_fd = fd; 124 ktp->ktr_rw = rw; 125 cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); 126 while (resid > 0) { 127 if ((cnt = iov->iov_len) > resid) 128 cnt = resid; 129 if (copyin(iov->iov_base, cp, cnt)) 130 goto done; 131 cp += cnt; 132 resid -= cnt; 133 iov++; 134 } 135 kth->ktr_buf = (caddr_t)ktp; 136 kth->ktr_len = sizeof (struct ktr_genio) + len; 137 138 ktrwrite(vp, kth); 139 done: 140 FREE(kth, M_TEMP); 141 FREE(ktp, M_TEMP); 142 } 143 144 ktrpsig(vp, sig, action, mask, code) 145 struct vnode *vp; 146 sig_t action; 147 { 148 struct ktr_header *kth = ktrgetheader(KTR_PSIG); 149 struct ktr_psig kp; 150 151 if (kth == NULL) 152 return; 153 kp.signo = (char)sig; 154 kp.action = action; 155 kp.mask = mask; 156 kp.code = code; 157 kth->ktr_buf = (caddr_t)&kp; 158 kth->ktr_len = sizeof (struct ktr_psig); 159 160 ktrwrite(vp, kth); 161 FREE(kth, M_TEMP); 162 } 163 164 /* Interface and common routines */ 165 166 /* 167 * ktrace system call 168 */ 169 ktrace() 170 { 171 register struct a { 172 char *fname; 173 int ops; 174 int facs; 175 int pid; 176 } *uap = (struct a *)u.u_ap; 177 register struct vnode *vp = NULL; 178 register struct nameidata *ndp = &u.u_nd; 179 register struct proc *p; 180 register ops = KTROP(uap->ops); 181 struct pgrp *pg; 182 register int facs = uap->facs; 183 register int ret = 0; 184 185 /* 186 * Until security implications are thought through, 187 * limit tracing to root (unless ktrace_nocheck is set). 188 */ 189 if (!ktrace_nocheck && (u.u_error = suser(u.u_cred, &u.u_acflag))) 190 return; 191 if (ops != KTROP_CLEAR) { 192 /* 193 * an operation which requires a file argument. 194 */ 195 ndp->ni_segflg = UIO_USERSPACE; 196 ndp->ni_dirp = uap->fname; 197 if (u.u_error = vn_open(ndp, FREAD|FWRITE, 0)) 198 return; 199 vp = ndp->ni_vp; 200 if (vp->v_type != VREG) { 201 u.u_error = EACCES; 202 vrele(vp); 203 return; 204 } 205 } 206 /* 207 * Clear all uses of the tracefile 208 */ 209 if (ops == KTROP_CLEARFILE) { 210 for (p = allproc; p != NULL; p = p->p_nxt) { 211 if (p->p_tracep == vp) { 212 p->p_tracep = NULL; 213 p->p_traceflag = 0; 214 vrele(vp); 215 } 216 } 217 goto done; 218 } 219 /* 220 * need something to (un)trace 221 */ 222 if (!facs) { 223 u.u_error = EINVAL; 224 goto done; 225 } 226 /* 227 * doit 228 */ 229 if (uap->pid < 0) { 230 pg = pgfind(-uap->pid); 231 if (pg == NULL) { 232 u.u_error = ESRCH; 233 goto done; 234 } 235 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) 236 if (uap->ops&KTRFLAG_DESCEND) 237 ret |= ktrsetchildren(p, ops, facs, vp); 238 else 239 ret |= ktrops(p, ops, facs, vp); 240 241 } else { 242 p = pfind(uap->pid); 243 if (p == NULL) { 244 u.u_error = ESRCH; 245 goto done; 246 } 247 if (ops&KTRFLAG_DESCEND) 248 ret |= ktrsetchildren(p, ops, facs, vp); 249 else 250 ret |= ktrops(p, ops, facs, vp); 251 } 252 if (!ret) 253 u.u_error = EPERM; 254 done: 255 if (vp != NULL) 256 vrele(vp); 257 } 258 259 ktrops(p, ops, facs, vp) 260 struct proc *p; 261 struct vnode *vp; 262 { 263 264 if (u.u_uid && u.u_uid != p->p_uid) 265 return 0; 266 if (ops == KTROP_SET) { 267 if (p->p_tracep != vp) { 268 /* 269 * if trace file already in use, relinquish 270 */ 271 if (p->p_tracep != NULL) 272 vrele(p->p_tracep); 273 VREF(vp); 274 p->p_tracep = vp; 275 } 276 p->p_traceflag |= facs; 277 } else { 278 /* KTROP_CLEAR */ 279 if (((p->p_traceflag &= ~facs) & ~KTRFAC_INHERIT) == 0) { 280 /* no more tracing */ 281 p->p_traceflag = 0; 282 if (p->p_tracep != NULL) { 283 vrele(p->p_tracep); 284 p->p_tracep = NULL; 285 } 286 } 287 } 288 289 return 1; 290 } 291 292 ktrsetchildren(top, ops, facs, vp) 293 struct proc *top; 294 struct vnode *vp; 295 { 296 register struct proc *p; 297 register int ndx; 298 register int ret = 0; 299 300 p = top; 301 for (;;) { 302 ret |= ktrops(p, ops, facs, vp); 303 /* 304 * If this process has children, descend to them next, 305 * otherwise do any siblings, and if done with this level, 306 * follow back up the tree (but not past top). 307 */ 308 if (p->p_cptr) 309 p = p->p_cptr; 310 else if (p == top) 311 return ret; 312 else if (p->p_osptr) 313 p = p->p_osptr; 314 else for (;;) { 315 p = p->p_pptr; 316 if (p == top) 317 return ret; 318 if (p->p_osptr) { 319 p = p->p_osptr; 320 break; 321 } 322 } 323 } 324 /*NOTREACHED*/ 325 } 326 327 ktrwrite(vp, kth) 328 struct vnode *vp; 329 register struct ktr_header *kth; 330 { 331 struct uio auio; 332 struct iovec aiov[2]; 333 int error; 334 335 if (vp == NULL) 336 return; 337 auio.uio_iov = &aiov[0]; 338 auio.uio_offset = 0; 339 auio.uio_segflg = UIO_SYSSPACE; 340 auio.uio_rw = UIO_WRITE; 341 aiov[0].iov_base = (caddr_t)kth; 342 aiov[0].iov_len = sizeof(struct ktr_header); 343 auio.uio_resid = sizeof(struct ktr_header); 344 auio.uio_iovcnt = 1; 345 if (kth->ktr_len > 0) { 346 auio.uio_iovcnt++; 347 aiov[1].iov_base = kth->ktr_buf; 348 aiov[1].iov_len = kth->ktr_len; 349 auio.uio_resid += kth->ktr_len; 350 } 351 VOP_LOCK(vp); 352 error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, u.u_cred); 353 VOP_UNLOCK(vp); 354 } 355 #endif 356