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