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