1 /* $OpenBSD: kern_ktrace.c,v 1.30 2003/06/02 23:28:05 millert Exp $ */ 2 /* $NetBSD: kern_ktrace.c,v 1.23 1996/02/09 18:59:36 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)kern_ktrace.c 8.2 (Berkeley) 9/23/93 33 */ 34 35 #ifdef KTRACE 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/proc.h> 40 #include <sys/file.h> 41 #include <sys/namei.h> 42 #include <sys/vnode.h> 43 #include <sys/ktrace.h> 44 #include <sys/malloc.h> 45 #include <sys/syslog.h> 46 47 #include <sys/mount.h> 48 #include <sys/syscallargs.h> 49 50 #include <uvm/uvm_extern.h> 51 52 void ktrinitheader(struct ktr_header *, struct proc *, int); 53 int ktrops(struct proc *, struct proc *, int, int, struct vnode *); 54 int ktrsetchildren(struct proc *, struct proc *, int, int, 55 struct vnode *); 56 int ktrwrite(struct proc *, struct ktr_header *); 57 int ktrcanset(struct proc *, struct proc *); 58 59 /* 60 * Change the trace vnode in a correct way (to avoid races). 61 */ 62 void 63 ktrsettracevnode(p, newvp) 64 struct proc *p; 65 struct vnode *newvp; 66 { 67 struct vnode *vp; 68 69 if (p->p_tracep == newvp) /* avoid work */ 70 return; 71 72 if (newvp != NULL) 73 VREF(newvp); 74 75 vp = p->p_tracep; 76 p->p_tracep = newvp; 77 78 if (vp != NULL) 79 vrele(vp); 80 } 81 82 void 83 ktrinitheader(kth, p, type) 84 struct ktr_header *kth; 85 struct proc *p; 86 int type; 87 { 88 bzero(kth, sizeof (struct ktr_header)); 89 kth->ktr_type = type; 90 microtime(&kth->ktr_time); 91 kth->ktr_pid = p->p_pid; 92 bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN); 93 } 94 95 void 96 ktrsyscall(p, code, argsize, args) 97 struct proc *p; 98 register_t code; 99 size_t argsize; 100 register_t args[]; 101 { 102 struct ktr_header kth; 103 struct ktr_syscall *ktp; 104 unsigned int len = sizeof(struct ktr_syscall) + argsize; 105 register_t *argp; 106 int i; 107 108 p->p_traceflag |= KTRFAC_ACTIVE; 109 ktrinitheader(&kth, p, KTR_SYSCALL); 110 ktp = malloc(len, M_TEMP, M_WAITOK); 111 ktp->ktr_code = code; 112 ktp->ktr_argsize = argsize; 113 argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall)); 114 for (i = 0; i < (argsize / sizeof *argp); i++) 115 *argp++ = args[i]; 116 kth.ktr_buf = (caddr_t)ktp; 117 kth.ktr_len = len; 118 ktrwrite(p, &kth); 119 free(ktp, M_TEMP); 120 p->p_traceflag &= ~KTRFAC_ACTIVE; 121 } 122 123 void 124 ktrsysret(p, code, error, retval) 125 struct proc *p; 126 register_t code; 127 int error; 128 register_t retval; 129 { 130 struct ktr_header kth; 131 struct ktr_sysret ktp; 132 133 p->p_traceflag |= KTRFAC_ACTIVE; 134 ktrinitheader(&kth, p, KTR_SYSRET); 135 ktp.ktr_code = code; 136 ktp.ktr_error = error; 137 ktp.ktr_retval = retval; /* what about val2 ? */ 138 139 kth.ktr_buf = (caddr_t)&ktp; 140 kth.ktr_len = sizeof(struct ktr_sysret); 141 142 ktrwrite(p, &kth); 143 p->p_traceflag &= ~KTRFAC_ACTIVE; 144 } 145 146 void 147 ktrnamei(p, path) 148 struct proc *p; 149 char *path; 150 { 151 struct ktr_header kth; 152 153 p->p_traceflag |= KTRFAC_ACTIVE; 154 ktrinitheader(&kth, p, KTR_NAMEI); 155 kth.ktr_len = strlen(path); 156 kth.ktr_buf = path; 157 158 ktrwrite(p, &kth); 159 p->p_traceflag &= ~KTRFAC_ACTIVE; 160 } 161 162 void 163 ktremul(p, emul) 164 struct proc *p; 165 char *emul; 166 { 167 struct ktr_header kth; 168 169 p->p_traceflag |= KTRFAC_ACTIVE; 170 ktrinitheader(&kth, p, KTR_EMUL); 171 kth.ktr_len = strlen(emul); 172 kth.ktr_buf = emul; 173 174 ktrwrite(p, &kth); 175 p->p_traceflag &= ~KTRFAC_ACTIVE; 176 } 177 178 void 179 ktrgenio(p, fd, rw, iov, len, error) 180 struct proc *p; 181 int fd; 182 enum uio_rw rw; 183 struct iovec *iov; 184 int len, error; 185 { 186 struct ktr_header kth; 187 struct ktr_genio *ktp; 188 caddr_t cp; 189 int resid = len, count; 190 int buflen; 191 192 if (error) 193 return; 194 195 p->p_traceflag |= KTRFAC_ACTIVE; 196 197 buflen = min(PAGE_SIZE, len + sizeof(struct ktr_genio)); 198 199 ktrinitheader(&kth, p, KTR_GENIO); 200 ktp = malloc(buflen, M_TEMP, M_WAITOK); 201 ktp->ktr_fd = fd; 202 ktp->ktr_rw = rw; 203 204 kth.ktr_buf = (caddr_t)ktp; 205 206 cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio)); 207 buflen -= sizeof(struct ktr_genio); 208 209 while (resid > 0) { 210 /* 211 * Don't allow this process to hog the cpu when doing 212 * huge I/O. 213 */ 214 if (p->p_schedflags & PSCHED_SHOULDYIELD) 215 preempt(NULL); 216 217 count = min(iov->iov_len, buflen); 218 if (count > resid) 219 count = resid; 220 if (copyin(iov->iov_base, cp, count)) 221 break; 222 223 kth.ktr_len = count + sizeof(struct ktr_genio); 224 225 if (ktrwrite(p, &kth) != 0) 226 break; 227 228 iov->iov_len -= count; 229 iov->iov_base = (caddr_t)iov->iov_base + count; 230 231 if (iov->iov_len == 0) 232 iov++; 233 234 resid -= count; 235 } 236 237 free(ktp, M_TEMP); 238 p->p_traceflag &= ~KTRFAC_ACTIVE; 239 240 } 241 242 void 243 ktrpsig(p, sig, action, mask, code, si) 244 struct proc *p; 245 int sig; 246 sig_t action; 247 int mask, code; 248 siginfo_t *si; 249 { 250 struct ktr_header kth; 251 struct ktr_psig kp; 252 253 p->p_traceflag |= KTRFAC_ACTIVE; 254 ktrinitheader(&kth, p, KTR_PSIG); 255 kp.signo = (char)sig; 256 kp.action = action; 257 kp.mask = mask; 258 kp.code = code; 259 kp.si = *si; 260 kth.ktr_buf = (caddr_t)&kp; 261 kth.ktr_len = sizeof (struct ktr_psig); 262 263 ktrwrite(p, &kth); 264 p->p_traceflag &= ~KTRFAC_ACTIVE; 265 } 266 267 void 268 ktrcsw(p, out, user) 269 struct proc *p; 270 int out, user; 271 { 272 struct ktr_header kth; 273 struct ktr_csw kc; 274 275 p->p_traceflag |= KTRFAC_ACTIVE; 276 ktrinitheader(&kth, p, KTR_CSW); 277 kc.out = out; 278 kc.user = user; 279 kth.ktr_buf = (caddr_t)&kc; 280 kth.ktr_len = sizeof (struct ktr_csw); 281 282 ktrwrite(p, &kth); 283 p->p_traceflag &= ~KTRFAC_ACTIVE; 284 } 285 286 /* Interface and common routines */ 287 288 /* 289 * ktrace system call 290 */ 291 /* ARGSUSED */ 292 int 293 sys_ktrace(curp, v, retval) 294 struct proc *curp; 295 void *v; 296 register_t *retval; 297 { 298 struct sys_ktrace_args /* { 299 syscallarg(char *) fname; 300 syscallarg(int) ops; 301 syscallarg(int) facs; 302 syscallarg(pid_t) pid; 303 } */ *uap = v; 304 struct vnode *vp = NULL; 305 struct proc *p = NULL; 306 struct pgrp *pg; 307 int facs = SCARG(uap, facs) & ~((unsigned) KTRFAC_ROOT); 308 int ops = KTROP(SCARG(uap, ops)); 309 int descend = SCARG(uap, ops) & KTRFLAG_DESCEND; 310 int ret = 0; 311 int error = 0; 312 struct nameidata nd; 313 314 curp->p_traceflag |= KTRFAC_ACTIVE; 315 if (ops != KTROP_CLEAR) { 316 /* 317 * an operation which requires a file argument. 318 */ 319 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname), 320 curp); 321 if ((error = vn_open(&nd, FREAD|FWRITE|O_NOFOLLOW, 0)) != 0) { 322 curp->p_traceflag &= ~KTRFAC_ACTIVE; 323 return (error); 324 } 325 vp = nd.ni_vp; 326 327 VOP_UNLOCK(vp, 0, curp); 328 if (vp->v_type != VREG) { 329 (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp); 330 curp->p_traceflag &= ~KTRFAC_ACTIVE; 331 return (EACCES); 332 } 333 } 334 /* 335 * Clear all uses of the tracefile 336 */ 337 if (ops == KTROP_CLEARFILE) { 338 for (p = LIST_FIRST(&allproc); p; p = LIST_NEXT(p, p_list)) { 339 if (p->p_tracep == vp) { 340 if (ktrcanset(curp, p)) { 341 p->p_traceflag = 0; 342 ktrsettracevnode(p, NULL); 343 } else 344 error = EPERM; 345 } 346 } 347 goto done; 348 } 349 /* 350 * need something to (un)trace (XXX - why is this here?) 351 */ 352 if (!facs) { 353 error = EINVAL; 354 goto done; 355 } 356 /* 357 * do it 358 */ 359 if (SCARG(uap, pid) < 0) { 360 /* 361 * by process group 362 */ 363 pg = pgfind(-SCARG(uap, pid)); 364 if (pg == NULL) { 365 error = ESRCH; 366 goto done; 367 } 368 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) 369 if (descend) 370 ret |= ktrsetchildren(curp, p, ops, facs, vp); 371 else 372 ret |= ktrops(curp, p, ops, facs, vp); 373 374 } else { 375 /* 376 * by pid 377 */ 378 p = pfind(SCARG(uap, pid)); 379 if (p == NULL) { 380 error = ESRCH; 381 goto done; 382 } 383 if (descend) 384 ret |= ktrsetchildren(curp, p, ops, facs, vp); 385 else 386 ret |= ktrops(curp, p, ops, facs, vp); 387 } 388 if (!ret) 389 error = EPERM; 390 done: 391 if (vp != NULL) 392 (void) vn_close(vp, FWRITE, curp->p_ucred, curp); 393 curp->p_traceflag &= ~KTRFAC_ACTIVE; 394 return (error); 395 } 396 397 int 398 ktrops(curp, p, ops, facs, vp) 399 struct proc *p, *curp; 400 int ops, facs; 401 struct vnode *vp; 402 { 403 404 if (!ktrcanset(curp, p)) 405 return (0); 406 if (ops == KTROP_SET) { 407 ktrsettracevnode(p, vp); 408 p->p_traceflag |= facs; 409 if (curp->p_ucred->cr_uid == 0) 410 p->p_traceflag |= KTRFAC_ROOT; 411 } else { 412 /* KTROP_CLEAR */ 413 if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { 414 /* no more tracing */ 415 p->p_traceflag = 0; 416 ktrsettracevnode(p, NULL); 417 } 418 } 419 420 /* 421 * Emit an emulation record, every time there is a ktrace 422 * change/attach request. 423 */ 424 if (KTRPOINT(p, KTR_EMUL)) 425 ktremul(p, p->p_emul->e_name); 426 427 return (1); 428 } 429 430 int 431 ktrsetchildren(curp, top, ops, facs, vp) 432 struct proc *curp, *top; 433 int ops, facs; 434 struct vnode *vp; 435 { 436 struct proc *p; 437 int ret = 0; 438 439 p = top; 440 for (;;) { 441 ret |= ktrops(curp, p, ops, facs, vp); 442 /* 443 * If this process has children, descend to them next, 444 * otherwise do any siblings, and if done with this level, 445 * follow back up the tree (but not past top). 446 */ 447 if (p->p_children.lh_first) 448 p = p->p_children.lh_first; 449 else for (;;) { 450 if (p == top) 451 return (ret); 452 if (p->p_sibling.le_next) { 453 p = p->p_sibling.le_next; 454 break; 455 } 456 p = p->p_pptr; 457 } 458 } 459 /*NOTREACHED*/ 460 } 461 462 int 463 ktrwrite(p, kth) 464 struct proc *p; 465 struct ktr_header *kth; 466 { 467 struct uio auio; 468 struct iovec aiov[2]; 469 int error; 470 struct vnode *vp = p->p_tracep; 471 472 if (vp == NULL) 473 return 0; 474 auio.uio_iov = &aiov[0]; 475 auio.uio_offset = 0; 476 auio.uio_segflg = UIO_SYSSPACE; 477 auio.uio_rw = UIO_WRITE; 478 aiov[0].iov_base = (caddr_t)kth; 479 aiov[0].iov_len = sizeof(struct ktr_header); 480 auio.uio_resid = sizeof(struct ktr_header); 481 auio.uio_iovcnt = 1; 482 auio.uio_procp = (struct proc *)0; 483 if (kth->ktr_len > 0) { 484 auio.uio_iovcnt++; 485 aiov[1].iov_base = kth->ktr_buf; 486 aiov[1].iov_len = kth->ktr_len; 487 auio.uio_resid += kth->ktr_len; 488 } 489 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 490 error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred); 491 VOP_UNLOCK(vp, 0, p); 492 if (!error) 493 return 0; 494 /* 495 * If error encountered, give up tracing on this vnode. 496 */ 497 log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", 498 error); 499 for (p = LIST_FIRST(&allproc); p != NULL; p = LIST_NEXT(p, p_list)) { 500 if (p->p_tracep == vp) { 501 p->p_traceflag = 0; 502 ktrsettracevnode(p, NULL); 503 } 504 } 505 506 return error; 507 } 508 509 /* 510 * Return true if caller has permission to set the ktracing state 511 * of target. Essentially, the target can't possess any 512 * more permissions than the caller. KTRFAC_ROOT signifies that 513 * root previously set the tracing status on the target process, and 514 * so, only root may further change it. 515 * 516 * TODO: check groups. use caller effective gid. 517 */ 518 int 519 ktrcanset(callp, targetp) 520 struct proc *callp, *targetp; 521 { 522 struct pcred *caller = callp->p_cred; 523 struct pcred *target = targetp->p_cred; 524 525 if ((caller->pc_ucred->cr_uid == target->p_ruid && 526 target->p_ruid == target->p_svuid && 527 caller->p_rgid == target->p_rgid && /* XXX */ 528 target->p_rgid == target->p_svgid && 529 (targetp->p_traceflag & KTRFAC_ROOT) == 0 && 530 !ISSET(targetp->p_flag, P_SUGID)) || 531 caller->pc_ucred->cr_uid == 0) 532 return (1); 533 534 return (0); 535 } 536 537 #endif 538