1 /* $NetBSD: kern_ktrace.c,v 1.77 2003/08/07 16:31:45 agc 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)kern_ktrace.c 8.5 (Berkeley) 5/14/95 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: kern_ktrace.c,v 1.77 2003/08/07 16:31:45 agc Exp $"); 36 37 #include "opt_ktrace.h" 38 #include "opt_compat_mach.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/proc.h> 43 #include <sys/file.h> 44 #include <sys/namei.h> 45 #include <sys/vnode.h> 46 #include <sys/ktrace.h> 47 #include <sys/malloc.h> 48 #include <sys/syslog.h> 49 #include <sys/filedesc.h> 50 #include <sys/ioctl.h> 51 52 #include <sys/mount.h> 53 #include <sys/sa.h> 54 #include <sys/syscallargs.h> 55 56 #ifdef KTRACE 57 58 int ktrace_common(struct proc *, int, int, int, struct file *); 59 void ktrinitheader(struct ktr_header *, struct proc *, int); 60 int ktrops(struct proc *, struct proc *, int, int, struct file *); 61 int ktrsetchildren(struct proc *, struct proc *, int, int, 62 struct file *); 63 int ktrwrite(struct proc *, struct ktr_header *); 64 int ktrcanset(struct proc *, struct proc *); 65 int ktrsamefile(struct file *, struct file *); 66 67 /* 68 * "deep" compare of two files for the purposes of clearing a trace. 69 * Returns true if they're the same open file, or if they point at the 70 * same underlying vnode/socket. 71 */ 72 73 int 74 ktrsamefile(f1, f2) 75 struct file *f1; 76 struct file *f2; 77 { 78 return ((f1 == f2) || 79 ((f1 != NULL) && (f2 != NULL) && 80 (f1->f_type == f2->f_type) && 81 (f1->f_data == f2->f_data))); 82 } 83 84 void 85 ktrderef(p) 86 struct proc *p; 87 { 88 struct file *fp = p->p_tracep; 89 p->p_traceflag = 0; 90 if (fp == NULL) 91 return; 92 simple_lock(&fp->f_slock); 93 FILE_USE(fp); 94 95 /* 96 * ktrace file descriptor can't be watched (are not visible to 97 * userspace), so no kqueue stuff here 98 */ 99 closef(fp, NULL); 100 101 p->p_tracep = NULL; 102 } 103 104 void 105 ktradref(p) 106 struct proc *p; 107 { 108 struct file *fp = p->p_tracep; 109 110 fp->f_count++; 111 } 112 113 void 114 ktrinitheader(kth, p, type) 115 struct ktr_header *kth; 116 struct proc *p; 117 int type; 118 { 119 120 memset(kth, 0, sizeof(*kth)); 121 kth->ktr_type = type; 122 microtime(&kth->ktr_time); 123 kth->ktr_pid = p->p_pid; 124 memcpy(kth->ktr_comm, p->p_comm, MAXCOMLEN); 125 } 126 127 void 128 ktrsyscall(p, code, realcode, callp, args) 129 struct proc *p; 130 register_t code; 131 register_t realcode; 132 const struct sysent *callp; 133 register_t args[]; 134 { 135 struct ktr_header kth; 136 struct ktr_syscall *ktp; 137 register_t *argp; 138 int argsize; 139 size_t len; 140 u_int i; 141 142 if (callp == NULL) 143 callp = p->p_emul->e_sysent; 144 145 argsize = callp[code].sy_argsize; 146 len = sizeof(struct ktr_syscall) + argsize; 147 148 p->p_traceflag |= KTRFAC_ACTIVE; 149 ktrinitheader(&kth, p, KTR_SYSCALL); 150 ktp = malloc(len, M_TEMP, M_WAITOK); 151 ktp->ktr_code = realcode; 152 ktp->ktr_argsize = argsize; 153 argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall)); 154 for (i = 0; i < (argsize / sizeof(*argp)); i++) 155 *argp++ = args[i]; 156 kth.ktr_buf = (caddr_t)ktp; 157 kth.ktr_len = len; 158 (void) ktrwrite(p, &kth); 159 free(ktp, M_TEMP); 160 p->p_traceflag &= ~KTRFAC_ACTIVE; 161 } 162 163 void 164 ktrsysret(p, code, error, retval) 165 struct proc *p; 166 register_t code; 167 int error; 168 register_t *retval; 169 { 170 struct ktr_header kth; 171 struct ktr_sysret ktp; 172 173 p->p_traceflag |= KTRFAC_ACTIVE; 174 ktrinitheader(&kth, p, KTR_SYSRET); 175 ktp.ktr_code = code; 176 ktp.ktr_eosys = 0; /* XXX unused */ 177 ktp.ktr_error = error; 178 ktp.ktr_retval = retval ? retval[0] : 0; 179 ktp.ktr_retval_1 = retval ? retval[1] : 0; 180 181 kth.ktr_buf = (caddr_t)&ktp; 182 kth.ktr_len = sizeof(struct ktr_sysret); 183 184 (void) ktrwrite(p, &kth); 185 p->p_traceflag &= ~KTRFAC_ACTIVE; 186 } 187 188 void 189 ktrnamei(p, path) 190 struct proc *p; 191 char *path; 192 { 193 struct ktr_header kth; 194 195 p->p_traceflag |= KTRFAC_ACTIVE; 196 ktrinitheader(&kth, p, KTR_NAMEI); 197 kth.ktr_len = strlen(path); 198 kth.ktr_buf = path; 199 200 (void) ktrwrite(p, &kth); 201 p->p_traceflag &= ~KTRFAC_ACTIVE; 202 } 203 204 void 205 ktremul(p) 206 struct proc *p; 207 { 208 struct ktr_header kth; 209 const char *emul = p->p_emul->e_name; 210 211 p->p_traceflag |= KTRFAC_ACTIVE; 212 ktrinitheader(&kth, p, KTR_EMUL); 213 kth.ktr_len = strlen(emul); 214 kth.ktr_buf = (caddr_t)emul; 215 216 (void) ktrwrite(p, &kth); 217 p->p_traceflag &= ~KTRFAC_ACTIVE; 218 } 219 220 void 221 ktrkmem(struct proc *p, int ktr, const void *buf, size_t len) 222 { 223 struct ktr_header kth; 224 225 p->p_traceflag |= KTRFAC_ACTIVE; 226 ktrinitheader(&kth, p, ktr); 227 kth.ktr_len = len; 228 kth.ktr_buf = buf; 229 230 (void)ktrwrite(p, &kth); 231 p->p_traceflag &= ~KTRFAC_ACTIVE; 232 } 233 234 void 235 ktrgenio(p, fd, rw, iov, len, error) 236 struct proc *p; 237 int fd; 238 enum uio_rw rw; 239 struct iovec *iov; 240 int len; 241 int error; 242 { 243 struct ktr_header kth; 244 struct ktr_genio *ktp; 245 caddr_t cp; 246 int resid = len, cnt; 247 int buflen; 248 249 if (error) 250 return; 251 252 p->p_traceflag |= KTRFAC_ACTIVE; 253 254 buflen = min(PAGE_SIZE, len + sizeof(struct ktr_genio)); 255 256 ktrinitheader(&kth, p, KTR_GENIO); 257 ktp = malloc(buflen, M_TEMP, M_WAITOK); 258 ktp->ktr_fd = fd; 259 ktp->ktr_rw = rw; 260 261 kth.ktr_buf = (caddr_t)ktp; 262 263 cp = (caddr_t)((char *)ktp + sizeof(struct ktr_genio)); 264 buflen -= sizeof(struct ktr_genio); 265 266 while (resid > 0) { 267 #if 0 /* XXX NJWLWP */ 268 KDASSERT(p->p_cpu != NULL); 269 KDASSERT(p->p_cpu == curcpu()); 270 #endif 271 /* XXX NJWLWP */ 272 if (curcpu()->ci_schedstate.spc_flags & SPCF_SHOULDYIELD) 273 preempt(1); 274 275 cnt = min(iov->iov_len, buflen); 276 if (cnt > resid) 277 cnt = resid; 278 if (copyin(iov->iov_base, cp, cnt)) 279 break; 280 281 kth.ktr_len = cnt + sizeof(struct ktr_genio); 282 283 if (__predict_false(ktrwrite(p, &kth) != 0)) 284 break; 285 286 iov->iov_base = (caddr_t)iov->iov_base + cnt; 287 iov->iov_len -= cnt; 288 289 if (iov->iov_len == 0) 290 iov++; 291 292 resid -= cnt; 293 } 294 295 free(ktp, M_TEMP); 296 p->p_traceflag &= ~KTRFAC_ACTIVE; 297 } 298 299 void 300 ktrpsig(p, sig, action, mask, code) 301 struct proc *p; 302 int sig; 303 sig_t action; 304 sigset_t *mask; 305 int code; 306 { 307 struct ktr_header kth; 308 struct ktr_psig kp; 309 310 p->p_traceflag |= KTRFAC_ACTIVE; 311 ktrinitheader(&kth, p, KTR_PSIG); 312 kp.signo = (char)sig; 313 kp.action = action; 314 kp.mask = *mask; 315 kp.code = code; 316 kth.ktr_buf = (caddr_t)&kp; 317 kth.ktr_len = sizeof(struct ktr_psig); 318 319 (void) ktrwrite(p, &kth); 320 p->p_traceflag &= ~KTRFAC_ACTIVE; 321 } 322 323 void 324 ktrcsw(p, out, user) 325 struct proc *p; 326 int out; 327 int user; 328 { 329 struct ktr_header kth; 330 struct ktr_csw kc; 331 332 p->p_traceflag |= KTRFAC_ACTIVE; 333 ktrinitheader(&kth, p, KTR_CSW); 334 kc.out = out; 335 kc.user = user; 336 kth.ktr_buf = (caddr_t)&kc; 337 kth.ktr_len = sizeof(struct ktr_csw); 338 339 (void) ktrwrite(p, &kth); 340 p->p_traceflag &= ~KTRFAC_ACTIVE; 341 } 342 343 void 344 ktruser(p, id, addr, len, ustr) 345 struct proc *p; 346 const char *id; 347 void *addr; 348 size_t len; 349 int ustr; 350 { 351 struct ktr_header kth; 352 struct ktr_user *ktp; 353 caddr_t user_dta; 354 355 p->p_traceflag |= KTRFAC_ACTIVE; 356 ktrinitheader(&kth, p, KTR_USER); 357 ktp = malloc(sizeof(struct ktr_user) + len, M_TEMP, M_WAITOK); 358 if (ustr) { 359 if (copyinstr(id, ktp->ktr_id, KTR_USER_MAXIDLEN, NULL) != 0) 360 ktp->ktr_id[0] = '\0'; 361 } else 362 strncpy(ktp->ktr_id, id, KTR_USER_MAXIDLEN); 363 ktp->ktr_id[KTR_USER_MAXIDLEN-1] = '\0'; 364 365 user_dta = (caddr_t) ((char *)ktp + sizeof(struct ktr_user)); 366 if (copyin(addr, (void *) user_dta, len) != 0) 367 len = 0; 368 369 kth.ktr_buf = (void *)ktp; 370 kth.ktr_len = sizeof(struct ktr_user) + len; 371 (void) ktrwrite(p, &kth); 372 373 free(ktp, M_TEMP); 374 p->p_traceflag &= ~KTRFAC_ACTIVE; 375 376 } 377 378 void 379 ktrmmsg(p, msgh, size) 380 struct proc *p; 381 const void *msgh; 382 size_t size; 383 { 384 struct ktr_header kth; 385 struct ktr_mmsg *kp; 386 387 p->p_traceflag |= KTRFAC_ACTIVE; 388 ktrinitheader(&kth, p, KTR_MMSG); 389 390 kp = (struct ktr_mmsg *)msgh; 391 kth.ktr_buf = (caddr_t)kp; 392 kth.ktr_len = size; 393 (void) ktrwrite(p, &kth); 394 p->p_traceflag &= ~KTRFAC_ACTIVE; 395 } 396 397 /* Interface and common routines */ 398 399 int 400 ktrace_common(curp, ops, facs, pid, fp) 401 struct proc *curp; 402 int ops; 403 int facs; 404 int pid; 405 struct file *fp; 406 { 407 int ret = 0; 408 int error = 0; 409 int one = 1; 410 int descend; 411 struct proc *p; 412 struct pgrp *pg; 413 414 curp->p_traceflag |= KTRFAC_ACTIVE; 415 descend = ops & KTRFLAG_DESCEND; 416 facs = facs & ~((unsigned) KTRFAC_ROOT); 417 418 /* 419 * Clear all uses of the tracefile 420 */ 421 if (KTROP(ops) == KTROP_CLEARFILE) { 422 proclist_lock_read(); 423 for (p = LIST_FIRST(&allproc); p != NULL; 424 p = LIST_NEXT(p, p_list)) { 425 if (ktrsamefile(p->p_tracep, fp)) { 426 if (ktrcanset(curp, p)) 427 ktrderef(p); 428 else 429 error = EPERM; 430 } 431 } 432 proclist_unlock_read(); 433 goto done; 434 } 435 436 /* 437 * Mark fp non-blocking, to avoid problems from possible deadlocks. 438 */ 439 440 if (fp != NULL) { 441 fp->f_flag |= FNONBLOCK; 442 (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&one, curp); 443 } 444 445 /* 446 * need something to (un)trace (XXX - why is this here?) 447 */ 448 if (!facs) { 449 error = EINVAL; 450 goto done; 451 } 452 /* 453 * do it 454 */ 455 if (pid < 0) { 456 /* 457 * by process group 458 */ 459 pg = pgfind(-pid); 460 if (pg == NULL) { 461 error = ESRCH; 462 goto done; 463 } 464 for (p = LIST_FIRST(&pg->pg_members); p != NULL; 465 p = LIST_NEXT(p, p_pglist)) { 466 if (descend) 467 ret |= ktrsetchildren(curp, p, ops, facs, fp); 468 else 469 ret |= ktrops(curp, p, ops, facs, fp); 470 } 471 472 } else { 473 /* 474 * by pid 475 */ 476 p = pfind(pid); 477 if (p == NULL) { 478 error = ESRCH; 479 goto done; 480 } 481 if (descend) 482 ret |= ktrsetchildren(curp, p, ops, facs, fp); 483 else 484 ret |= ktrops(curp, p, ops, facs, fp); 485 } 486 if (!ret) 487 error = EPERM; 488 done: 489 curp->p_traceflag &= ~KTRFAC_ACTIVE; 490 return (error); 491 } 492 493 /* 494 * ktrace system call 495 */ 496 /* ARGSUSED */ 497 int 498 sys_fktrace(l, v, retval) 499 struct lwp *l; 500 void *v; 501 register_t *retval; 502 { 503 struct sys_fktrace_args /* { 504 syscallarg(int) fd; 505 syscallarg(int) ops; 506 syscallarg(int) facs; 507 syscallarg(int) pid; 508 } */ *uap = v; 509 struct proc *curp = l->l_proc; 510 struct file *fp = NULL; 511 struct filedesc *fdp = curp->p_fd; 512 int error; 513 514 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) 515 return (EBADF); 516 517 FILE_USE(fp); 518 519 if ((fp->f_flag & FWRITE) == 0) 520 error = EBADF; 521 else 522 error = ktrace_common(curp, SCARG(uap, ops), 523 SCARG(uap, facs), SCARG(uap, pid), fp); 524 525 FILE_UNUSE(fp, curp); 526 527 return error; 528 } 529 530 /* 531 * ktrace system call 532 */ 533 /* ARGSUSED */ 534 int 535 sys_ktrace(l, v, retval) 536 struct lwp *l; 537 void *v; 538 register_t *retval; 539 { 540 struct sys_ktrace_args /* { 541 syscallarg(const char *) fname; 542 syscallarg(int) ops; 543 syscallarg(int) facs; 544 syscallarg(int) pid; 545 } */ *uap = v; 546 struct proc *curp = l->l_proc; 547 struct vnode *vp = NULL; 548 struct file *fp = NULL; 549 int fd; 550 int ops = SCARG(uap, ops); 551 int error = 0; 552 struct nameidata nd; 553 554 ops = KTROP(ops) | (ops & KTRFLAG_DESCEND); 555 556 curp->p_traceflag |= KTRFAC_ACTIVE; 557 if ((ops & KTROP_CLEAR) == 0) { 558 /* 559 * an operation which requires a file argument. 560 */ 561 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname), 562 curp); 563 if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) { 564 curp->p_traceflag &= ~KTRFAC_ACTIVE; 565 return (error); 566 } 567 vp = nd.ni_vp; 568 VOP_UNLOCK(vp, 0); 569 if (vp->v_type != VREG) { 570 (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp); 571 curp->p_traceflag &= ~KTRFAC_ACTIVE; 572 return (EACCES); 573 } 574 /* 575 * XXX This uses up a file descriptor slot in the 576 * tracing process for the duration of this syscall. 577 * This is not expected to be a problem. If 578 * falloc(NULL, ...) DTRT we could skip that part, but 579 * that would require changing its interface to allow 580 * the caller to pass in a ucred.. 581 * 582 * This will FILE_USE the fp it returns, if any. 583 * Keep it in use until we return. 584 */ 585 if ((error = falloc(curp, &fp, &fd)) != 0) 586 goto done; 587 588 fp->f_flag = FWRITE|FAPPEND; 589 fp->f_type = DTYPE_VNODE; 590 fp->f_ops = &vnops; 591 fp->f_data = (caddr_t)vp; 592 FILE_SET_MATURE(fp); 593 vp = NULL; 594 } 595 error = ktrace_common(curp, SCARG(uap, ops), SCARG(uap, facs), 596 SCARG(uap, pid), fp); 597 done: 598 if (vp != NULL) 599 (void) vn_close(vp, FWRITE, curp->p_ucred, curp); 600 if (fp != NULL) { 601 FILE_UNUSE(fp, curp); /* release file */ 602 fdrelease(curp, fd); /* release fd table slot */ 603 } 604 return (error); 605 } 606 607 int 608 ktrops(curp, p, ops, facs, fp) 609 struct proc *curp; 610 struct proc *p; 611 int ops; 612 int facs; 613 struct file *fp; 614 { 615 616 if (!ktrcanset(curp, p)) 617 return (0); 618 if (KTROP(ops) == KTROP_SET) { 619 if (p->p_tracep != fp) { 620 /* 621 * if trace file already in use, relinquish 622 */ 623 ktrderef(p); 624 p->p_tracep = fp; 625 ktradref(p); 626 } 627 p->p_traceflag |= facs; 628 if (curp->p_ucred->cr_uid == 0) 629 p->p_traceflag |= KTRFAC_ROOT; 630 } else { 631 /* KTROP_CLEAR */ 632 if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) { 633 /* no more tracing */ 634 ktrderef(p); 635 } 636 } 637 638 /* 639 * Emit an emulation record, every time there is a ktrace 640 * change/attach request. 641 */ 642 if (KTRPOINT(p, KTR_EMUL)) 643 ktremul(p); 644 #ifdef __HAVE_SYSCALL_INTERN 645 (*p->p_emul->e_syscall_intern)(p); 646 #endif 647 648 return (1); 649 } 650 651 int 652 ktrsetchildren(curp, top, ops, facs, fp) 653 struct proc *curp; 654 struct proc *top; 655 int ops; 656 int facs; 657 struct file *fp; 658 { 659 struct proc *p; 660 int ret = 0; 661 662 p = top; 663 for (;;) { 664 ret |= ktrops(curp, p, ops, facs, fp); 665 /* 666 * If this process has children, descend to them next, 667 * otherwise do any siblings, and if done with this level, 668 * follow back up the tree (but not past top). 669 */ 670 if (LIST_FIRST(&p->p_children) != NULL) 671 p = LIST_FIRST(&p->p_children); 672 else for (;;) { 673 if (p == top) 674 return (ret); 675 if (LIST_NEXT(p, p_sibling) != NULL) { 676 p = LIST_NEXT(p, p_sibling); 677 break; 678 } 679 p = p->p_pptr; 680 } 681 } 682 /*NOTREACHED*/ 683 } 684 685 int 686 ktrwrite(p, kth) 687 struct proc *p; 688 struct ktr_header *kth; 689 { 690 struct uio auio; 691 struct iovec aiov[2]; 692 int error, tries; 693 struct file *fp = p->p_tracep; 694 695 if (fp == NULL) 696 return 0; 697 698 auio.uio_iov = &aiov[0]; 699 auio.uio_offset = 0; 700 auio.uio_segflg = UIO_SYSSPACE; 701 auio.uio_rw = UIO_WRITE; 702 aiov[0].iov_base = (caddr_t)kth; 703 aiov[0].iov_len = sizeof(struct ktr_header); 704 auio.uio_resid = sizeof(struct ktr_header); 705 auio.uio_iovcnt = 1; 706 auio.uio_procp = (struct proc *)0; 707 if (kth->ktr_len > 0) { 708 auio.uio_iovcnt++; 709 aiov[1].iov_base = (void *)kth->ktr_buf; 710 aiov[1].iov_len = kth->ktr_len; 711 auio.uio_resid += kth->ktr_len; 712 } 713 714 simple_lock(&fp->f_slock); 715 FILE_USE(fp); 716 717 tries = 0; 718 do { 719 error = (*fp->f_ops->fo_write)(fp, &fp->f_offset, &auio, 720 fp->f_cred, FOF_UPDATE_OFFSET); 721 tries++; 722 if (error == EWOULDBLOCK) 723 preempt(1); 724 } while ((error == EWOULDBLOCK) && (tries < 3)); 725 FILE_UNUSE(fp, NULL); 726 727 if (__predict_true(error == 0)) 728 return (0); 729 /* 730 * If error encountered, give up tracing on this vnode. Don't report 731 * EPIPE as this can easily happen with fktrace()/ktruss. 732 */ 733 if (error != EPIPE) 734 log(LOG_NOTICE, 735 "ktrace write failed, errno %d, tracing stopped\n", 736 error); 737 proclist_lock_read(); 738 for (p = LIST_FIRST(&allproc); p != NULL; p = LIST_NEXT(p, p_list)) { 739 if (ktrsamefile(p->p_tracep, fp)) 740 ktrderef(p); 741 } 742 proclist_unlock_read(); 743 744 return (error); 745 } 746 747 /* 748 * Return true if caller has permission to set the ktracing state 749 * of target. Essentially, the target can't possess any 750 * more permissions than the caller. KTRFAC_ROOT signifies that 751 * root previously set the tracing status on the target process, and 752 * so, only root may further change it. 753 * 754 * TODO: check groups. use caller effective gid. 755 */ 756 int 757 ktrcanset(callp, targetp) 758 struct proc *callp; 759 struct proc *targetp; 760 { 761 struct pcred *caller = callp->p_cred; 762 struct pcred *target = targetp->p_cred; 763 764 if ((caller->pc_ucred->cr_uid == target->p_ruid && 765 target->p_ruid == target->p_svuid && 766 caller->p_rgid == target->p_rgid && /* XXX */ 767 target->p_rgid == target->p_svgid && 768 (targetp->p_traceflag & KTRFAC_ROOT) == 0 && 769 (targetp->p_flag & P_SUGID) == 0) || 770 caller->pc_ucred->cr_uid == 0) 771 return (1); 772 773 return (0); 774 } 775 #endif /* KTRACE */ 776 777 /* 778 * Put user defined entry to ktrace records. 779 */ 780 int 781 sys_utrace(l, v, retval) 782 struct lwp *l; 783 void *v; 784 register_t *retval; 785 { 786 #ifdef KTRACE 787 struct sys_utrace_args /* { 788 syscallarg(const char *) label; 789 syscallarg(void *) addr; 790 syscallarg(size_t) len; 791 } */ *uap = v; 792 struct proc *p = l->l_proc; 793 if (!KTRPOINT(p, KTR_USER)) 794 return (0); 795 796 if (SCARG(uap, len) > KTR_USER_MAXLEN) 797 return (EINVAL); 798 799 ktruser(p, SCARG(uap, label), SCARG(uap, addr), SCARG(uap, len), 1); 800 801 return (0); 802 #else /* !KTRACE */ 803 return ENOSYS; 804 #endif /* KTRACE */ 805 } 806