1 /* $NetBSD: kern_ktrace.c,v 1.33 1998/09/11 12:50:10 mycroft 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 closef(fp, NULL); 73 } else { 74 struct vnode *vp = p->p_tracep; 75 76 vrele(vp); 77 } 78 p->p_tracep = NULL; 79 p->p_traceflag = 0; 80 } 81 82 void 83 ktradref(p) 84 struct proc *p; 85 { 86 if (p->p_traceflag & KTRFAC_FD) { 87 struct file *fp = p->p_tracep; 88 89 fp->f_count++; 90 } else { 91 struct vnode *vp = p->p_tracep; 92 93 VREF(vp); 94 } 95 } 96 97 struct ktr_header * 98 ktrgetheader(type) 99 int type; 100 { 101 struct ktr_header *kth; 102 struct proc *p = curproc; /* XXX */ 103 104 MALLOC(kth, struct ktr_header *, sizeof(struct ktr_header), 105 M_TEMP, M_WAITOK); 106 kth->ktr_type = type; 107 microtime(&kth->ktr_time); 108 kth->ktr_pid = p->p_pid; 109 memcpy(kth->ktr_comm, p->p_comm, MAXCOMLEN); 110 return (kth); 111 } 112 113 void 114 ktrsyscall(v, code, argsize, args) 115 void *v; 116 register_t code; 117 size_t argsize; 118 register_t args[]; 119 { 120 struct ktr_header *kth; 121 struct ktr_syscall *ktp; 122 struct proc *p = curproc; /* XXX */ 123 register_t *argp; 124 int len = sizeof(struct ktr_syscall) + argsize; 125 int i; 126 127 p->p_traceflag |= KTRFAC_ACTIVE; 128 kth = ktrgetheader(KTR_SYSCALL); 129 MALLOC(ktp, struct ktr_syscall *, len, M_TEMP, M_WAITOK); 130 ktp->ktr_code = code; 131 ktp->ktr_argsize = argsize; 132 argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall)); 133 for (i = 0; i < (argsize / sizeof(*argp)); i++) 134 *argp++ = args[i]; 135 kth->ktr_buf = (caddr_t)ktp; 136 kth->ktr_len = len; 137 ktrwrite(p, v, kth); 138 FREE(ktp, M_TEMP); 139 FREE(kth, M_TEMP); 140 p->p_traceflag &= ~KTRFAC_ACTIVE; 141 } 142 143 void 144 ktrsysret(v, code, error, retval) 145 void *v; 146 register_t code; 147 int error; 148 register_t retval; 149 { 150 struct ktr_header *kth; 151 struct ktr_sysret ktp; 152 struct proc *p = curproc; /* XXX */ 153 154 p->p_traceflag |= KTRFAC_ACTIVE; 155 kth = ktrgetheader(KTR_SYSRET); 156 ktp.ktr_code = code; 157 ktp.ktr_error = error; 158 ktp.ktr_retval = retval; /* what about val2 ? */ 159 160 kth->ktr_buf = (caddr_t)&ktp; 161 kth->ktr_len = sizeof(struct ktr_sysret); 162 163 ktrwrite(p, v, kth); 164 FREE(kth, M_TEMP); 165 p->p_traceflag &= ~KTRFAC_ACTIVE; 166 } 167 168 void 169 ktrnamei(v, path) 170 void *v; 171 char *path; 172 { 173 struct ktr_header *kth; 174 struct proc *p = curproc; /* XXX */ 175 176 p->p_traceflag |= KTRFAC_ACTIVE; 177 kth = ktrgetheader(KTR_NAMEI); 178 kth->ktr_len = strlen(path); 179 kth->ktr_buf = path; 180 181 ktrwrite(p, v, kth); 182 FREE(kth, M_TEMP); 183 p->p_traceflag &= ~KTRFAC_ACTIVE; 184 } 185 186 void 187 ktremul(v, p, emul) 188 void *v; 189 struct proc *p; 190 char *emul; 191 { 192 struct ktr_header *kth; 193 194 p->p_traceflag |= KTRFAC_ACTIVE; 195 kth = ktrgetheader(KTR_EMUL); 196 kth->ktr_len = strlen(emul); 197 kth->ktr_buf = emul; 198 199 ktrwrite(p, v, kth); 200 FREE(kth, M_TEMP); 201 p->p_traceflag &= ~KTRFAC_ACTIVE; 202 } 203 204 void 205 ktrgenio(v, fd, rw, iov, len, error) 206 void *v; 207 int fd; 208 enum uio_rw rw; 209 struct iovec *iov; 210 int len, error; 211 { 212 struct ktr_header *kth; 213 struct ktr_genio *ktp; 214 caddr_t cp; 215 int resid = len, cnt; 216 struct proc *p = curproc; /* XXX */ 217 218 if (error) 219 return; 220 p->p_traceflag |= KTRFAC_ACTIVE; 221 kth = ktrgetheader(KTR_GENIO); 222 MALLOC(ktp, struct ktr_genio *, sizeof(struct ktr_genio) + len, 223 M_TEMP, M_WAITOK); 224 ktp->ktr_fd = fd; 225 ktp->ktr_rw = rw; 226 cp = (caddr_t)((char *)ktp + sizeof(struct ktr_genio)); 227 while (resid > 0) { 228 if ((cnt = iov->iov_len) > resid) 229 cnt = resid; 230 if (copyin(iov->iov_base, cp, (unsigned)cnt)) 231 goto done; 232 cp += cnt; 233 resid -= cnt; 234 iov++; 235 } 236 kth->ktr_buf = (caddr_t)ktp; 237 kth->ktr_len = sizeof(struct ktr_genio) + len; 238 239 ktrwrite(p, v, kth); 240 done: 241 FREE(kth, M_TEMP); 242 FREE(ktp, M_TEMP); 243 p->p_traceflag &= ~KTRFAC_ACTIVE; 244 } 245 246 void 247 ktrpsig(v, sig, action, mask, code) 248 void *v; 249 int sig; 250 sig_t action; 251 sigset_t *mask; 252 int code; 253 { 254 struct ktr_header *kth; 255 struct ktr_psig kp; 256 struct proc *p = curproc; /* XXX */ 257 258 p->p_traceflag |= KTRFAC_ACTIVE; 259 kth = ktrgetheader(KTR_PSIG); 260 kp.signo = (char)sig; 261 kp.action = action; 262 kp.mask = *mask; 263 kp.code = code; 264 kth->ktr_buf = (caddr_t)&kp; 265 kth->ktr_len = sizeof(struct ktr_psig); 266 267 ktrwrite(p, v, kth); 268 FREE(kth, M_TEMP); 269 p->p_traceflag &= ~KTRFAC_ACTIVE; 270 } 271 272 void 273 ktrcsw(v, out, user) 274 void *v; 275 int out, user; 276 { 277 struct ktr_header *kth; 278 struct ktr_csw kc; 279 struct proc *p = curproc; /* XXX */ 280 281 p->p_traceflag |= KTRFAC_ACTIVE; 282 kth = ktrgetheader(KTR_CSW); 283 kc.out = out; 284 kc.user = user; 285 kth->ktr_buf = (caddr_t)&kc; 286 kth->ktr_len = sizeof(struct ktr_csw); 287 288 ktrwrite(p, v, kth); 289 FREE(kth, M_TEMP); 290 p->p_traceflag &= ~KTRFAC_ACTIVE; 291 } 292 293 /* Interface and common routines */ 294 295 /* 296 * ktrace system call 297 */ 298 /* ARGSUSED */ 299 int 300 sys_fktrace(curp, v, retval) 301 struct proc *curp; 302 void *v; 303 register_t *retval; 304 { 305 struct sys_fktrace_args /* { 306 syscallarg(int) fd; 307 syscallarg(int) ops; 308 syscallarg(int) facs; 309 syscallarg(int) pid; 310 } */ *uap = v; 311 struct file *fp = NULL; 312 struct proc *p; 313 struct filedesc *fdp = curp->p_fd; 314 struct pgrp *pg; 315 int facs; 316 int ops; 317 int descend; 318 int ret = 0; 319 int error = 0; 320 321 if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles || 322 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL || 323 (fp->f_flag & FWRITE) == 0) 324 return (EBADF); 325 326 ops = KTROP(SCARG(uap, ops)) | KTRFLAG_FD; 327 descend = SCARG(uap, ops) & KTRFLAG_DESCEND; 328 facs = SCARG(uap, facs) & ~((unsigned) KTRFAC_ROOT); 329 curp->p_traceflag |= KTRFAC_ACTIVE; 330 331 /* 332 * Clear all uses of the tracefile 333 */ 334 if (KTROP(ops) == KTROP_CLEARFILE) { 335 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 336 if (p->p_tracep == fp) { 337 if (ktrcanset(curp, p)) 338 ktrderef(p); 339 else 340 error = EPERM; 341 } 342 } 343 goto done; 344 } 345 /* 346 * need something to (un)trace (XXX - why is this here?) 347 */ 348 if (!facs) { 349 error = EINVAL; 350 goto done; 351 } 352 /* 353 * do it 354 */ 355 if (SCARG(uap, pid) < 0) { 356 /* 357 * by process group 358 */ 359 pg = pgfind(-SCARG(uap, pid)); 360 if (pg == NULL) { 361 error = ESRCH; 362 goto done; 363 } 364 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) 365 if (descend) 366 ret |= ktrsetchildren(curp, p, ops, facs, fp); 367 else 368 ret |= ktrops(curp, p, ops, facs, fp); 369 370 } else { 371 /* 372 * by pid 373 */ 374 p = pfind(SCARG(uap, pid)); 375 if (p == NULL) { 376 error = ESRCH; 377 goto done; 378 } 379 if (descend) 380 ret |= ktrsetchildren(curp, p, ops, facs, fp); 381 else 382 ret |= ktrops(curp, p, ops, facs, fp); 383 } 384 if (!ret) 385 error = EPERM; 386 done: 387 curp->p_traceflag &= ~KTRFAC_ACTIVE; 388 return (error); 389 } 390 391 /* 392 * ktrace system call 393 */ 394 /* ARGSUSED */ 395 int 396 sys_ktrace(curp, v, retval) 397 struct proc *curp; 398 void *v; 399 register_t *retval; 400 { 401 struct sys_ktrace_args /* { 402 syscallarg(const char *) fname; 403 syscallarg(int) ops; 404 syscallarg(int) facs; 405 syscallarg(int) pid; 406 } */ *uap = v; 407 struct vnode *vp = NULL; 408 struct proc *p; 409 struct pgrp *pg; 410 int facs = SCARG(uap, facs) & ~((unsigned) KTRFAC_ROOT); 411 int ops = KTROP(SCARG(uap, ops)); 412 int descend = SCARG(uap, ops) & KTRFLAG_DESCEND; 413 int ret = 0; 414 int error = 0; 415 struct nameidata nd; 416 417 curp->p_traceflag |= KTRFAC_ACTIVE; 418 if (ops != KTROP_CLEAR) { 419 /* 420 * an operation which requires a file argument. 421 */ 422 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname), 423 curp); 424 if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) { 425 curp->p_traceflag &= ~KTRFAC_ACTIVE; 426 return (error); 427 } 428 vp = nd.ni_vp; 429 VOP_UNLOCK(vp, 0); 430 if (vp->v_type != VREG) { 431 (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp); 432 curp->p_traceflag &= ~KTRFAC_ACTIVE; 433 return (EACCES); 434 } 435 } 436 /* 437 * Clear all uses of the tracefile 438 */ 439 if (KTROP(ops) == KTROP_CLEARFILE) { 440 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 441 if (p->p_tracep == vp && 442 !ktrops(curp, p, KTROP_CLEAR, ~0, vp)) 443 error = EPERM; 444 } 445 goto done; 446 } 447 /* 448 * need something to (un)trace (XXX - why is this here?) 449 */ 450 if (!facs) { 451 error = EINVAL; 452 goto done; 453 } 454 /* 455 * do it 456 */ 457 if (SCARG(uap, pid) < 0) { 458 /* 459 * by process group 460 */ 461 pg = pgfind(-SCARG(uap, pid)); 462 if (pg == NULL) { 463 error = ESRCH; 464 goto done; 465 } 466 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) 467 if (descend) 468 ret |= ktrsetchildren(curp, p, ops, facs, vp); 469 else 470 ret |= ktrops(curp, p, ops, facs, vp); 471 472 } else { 473 /* 474 * by pid 475 */ 476 p = pfind(SCARG(uap, pid)); 477 if (p == NULL) { 478 error = ESRCH; 479 goto done; 480 } 481 if (descend) 482 ret |= ktrsetchildren(curp, p, ops, facs, vp); 483 else 484 ret |= ktrops(curp, p, ops, facs, vp); 485 } 486 if (!ret) 487 error = EPERM; 488 done: 489 if (vp != NULL) 490 (void) vn_close(vp, FWRITE, curp->p_ucred, curp); 491 curp->p_traceflag &= ~KTRFAC_ACTIVE; 492 return (error); 493 } 494 495 int 496 ktrops(curp, p, ops, facs, v) 497 struct proc *p, *curp; 498 int ops, facs; 499 void *v; 500 { 501 502 if (!ktrcanset(curp, p)) 503 return (0); 504 if (KTROP(ops) == KTROP_SET) { 505 if (p->p_tracep != v) { 506 /* 507 * if trace file already in use, relinquish 508 */ 509 ktrderef(p); 510 if (ops & KTRFLAG_FD) 511 p->p_traceflag = KTRFAC_FD; 512 p->p_tracep = v; 513 ktradref(p); 514 } 515 p->p_traceflag |= facs; 516 if (curp->p_ucred->cr_uid == 0) 517 p->p_traceflag |= KTRFAC_ROOT; 518 } else { 519 /* KTROP_CLEAR */ 520 if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { 521 /* no more tracing */ 522 ktrderef(p); 523 } 524 } 525 526 /* 527 * Emit an emulation record, every time there is a ktrace 528 * change/attach request. 529 */ 530 if (KTRPOINT(p, KTR_EMUL)) 531 ktremul(p->p_tracep, p, p->p_emul->e_name); 532 533 return (1); 534 } 535 536 int 537 ktrsetchildren(curp, top, ops, facs, v) 538 struct proc *curp, *top; 539 int ops, facs; 540 void *v; 541 { 542 struct proc *p; 543 int ret = 0; 544 545 p = top; 546 for (;;) { 547 ret |= ktrops(curp, p, ops, facs, v); 548 /* 549 * If this process has children, descend to them next, 550 * otherwise do any siblings, and if done with this level, 551 * follow back up the tree (but not past top). 552 */ 553 if (p->p_children.lh_first) 554 p = p->p_children.lh_first; 555 else for (;;) { 556 if (p == top) 557 return (ret); 558 if (p->p_sibling.le_next) { 559 p = p->p_sibling.le_next; 560 break; 561 } 562 p = p->p_pptr; 563 } 564 } 565 /*NOTREACHED*/ 566 } 567 568 void 569 ktrwrite(p, v, kth) 570 struct proc *p; 571 void *v; 572 struct ktr_header *kth; 573 { 574 struct uio auio; 575 struct iovec aiov[2]; 576 int error; 577 578 if (v == NULL) 579 return; 580 auio.uio_iov = &aiov[0]; 581 auio.uio_offset = 0; 582 auio.uio_segflg = UIO_SYSSPACE; 583 auio.uio_rw = UIO_WRITE; 584 aiov[0].iov_base = (caddr_t)kth; 585 aiov[0].iov_len = sizeof(struct ktr_header); 586 auio.uio_resid = sizeof(struct ktr_header); 587 auio.uio_iovcnt = 1; 588 auio.uio_procp = (struct proc *)0; 589 if (kth->ktr_len > 0) { 590 auio.uio_iovcnt++; 591 aiov[1].iov_base = kth->ktr_buf; 592 aiov[1].iov_len = kth->ktr_len; 593 auio.uio_resid += kth->ktr_len; 594 } 595 if (p->p_traceflag & KTRFAC_FD) { 596 struct file *fp = v; 597 598 error = (*fp->f_ops->fo_write)(fp, &fp->f_offset, &auio, 599 fp->f_cred, FOF_UPDATE_OFFSET); 600 } 601 else { 602 struct vnode *vp = v; 603 604 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 605 error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred); 606 VOP_UNLOCK(vp, 0); 607 } 608 if (!error) 609 return; 610 /* 611 * If error encountered, give up tracing on this vnode. 612 */ 613 log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n", 614 error); 615 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) { 616 if (p->p_tracep == v) 617 ktrderef(p); 618 } 619 } 620 621 /* 622 * Return true if caller has permission to set the ktracing state 623 * of target. Essentially, the target can't possess any 624 * more permissions than the caller. KTRFAC_ROOT signifies that 625 * root previously set the tracing status on the target process, and 626 * so, only root may further change it. 627 * 628 * TODO: check groups. use caller effective gid. 629 */ 630 int 631 ktrcanset(callp, targetp) 632 struct proc *callp, *targetp; 633 { 634 struct pcred *caller = callp->p_cred; 635 struct pcred *target = targetp->p_cred; 636 637 if ((caller->pc_ucred->cr_uid == target->p_ruid && 638 target->p_ruid == target->p_svuid && 639 caller->p_rgid == target->p_rgid && /* XXX */ 640 target->p_rgid == target->p_svgid && 641 (targetp->p_traceflag & KTRFAC_ROOT) == 0) || 642 caller->pc_ucred->cr_uid == 0) 643 return (1); 644 645 return (0); 646 } 647 648 #endif 649