Annotation of sys/kern/kern_ktrace.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: kern_ktrace.c,v 1.42 2007/05/16 17:27:30 art 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/sched.h>
! 41: #include <sys/file.h>
! 42: #include <sys/namei.h>
! 43: #include <sys/vnode.h>
! 44: #include <sys/ktrace.h>
! 45: #include <sys/malloc.h>
! 46: #include <sys/syslog.h>
! 47: #include <sys/sysctl.h>
! 48:
! 49: #include <sys/mount.h>
! 50: #include <sys/syscall.h>
! 51: #include <sys/syscallargs.h>
! 52:
! 53: #include <uvm/uvm_extern.h>
! 54:
! 55: void ktrinitheader(struct ktr_header *, struct proc *, int);
! 56: int ktrops(struct proc *, struct proc *, int, int, struct vnode *);
! 57: int ktrsetchildren(struct proc *, struct proc *, int, int,
! 58: struct vnode *);
! 59: int ktrwrite(struct proc *, struct ktr_header *);
! 60: int ktrcanset(struct proc *, struct proc *);
! 61:
! 62: /*
! 63: * Change the trace vnode in a correct way (to avoid races).
! 64: */
! 65: void
! 66: ktrsettracevnode(struct proc *p, struct vnode *newvp)
! 67: {
! 68: struct vnode *vp;
! 69:
! 70: if (p->p_tracep == newvp) /* avoid work */
! 71: return;
! 72:
! 73: if (newvp != NULL)
! 74: VREF(newvp);
! 75:
! 76: vp = p->p_tracep;
! 77: p->p_tracep = newvp;
! 78:
! 79: if (vp != NULL)
! 80: vrele(vp);
! 81: }
! 82:
! 83: void
! 84: ktrinitheader(struct ktr_header *kth, struct proc *p, int type)
! 85: {
! 86: bzero(kth, sizeof (struct ktr_header));
! 87: kth->ktr_type = type;
! 88: microtime(&kth->ktr_time);
! 89: kth->ktr_pid = p->p_pid;
! 90: bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN);
! 91: }
! 92:
! 93: void
! 94: ktrsyscall(struct proc *p, register_t code, size_t argsize, register_t args[])
! 95: {
! 96: struct ktr_header kth;
! 97: struct ktr_syscall *ktp;
! 98: size_t len = sizeof(struct ktr_syscall) + argsize;
! 99: register_t *argp;
! 100: u_int nargs = 0;
! 101: int i;
! 102:
! 103: if (code == SYS___sysctl && (p->p_emul->e_flags & EMUL_NATIVE)) {
! 104: /*
! 105: * The native sysctl encoding stores the mib[]
! 106: * array because it is interesting.
! 107: */
! 108: if (args[1] > 0)
! 109: nargs = min(args[1], CTL_MAXNAME);
! 110: len += nargs * sizeof(int);
! 111: }
! 112: p->p_traceflag |= KTRFAC_ACTIVE;
! 113: ktrinitheader(&kth, p, KTR_SYSCALL);
! 114: ktp = malloc(len, M_TEMP, M_WAITOK);
! 115: ktp->ktr_code = code;
! 116: ktp->ktr_argsize = argsize;
! 117: argp = (register_t *)((char *)ktp + sizeof(struct ktr_syscall));
! 118: for (i = 0; i < (argsize / sizeof *argp); i++)
! 119: *argp++ = args[i];
! 120: if (code == SYS___sysctl && (p->p_emul->e_flags & EMUL_NATIVE) &&
! 121: nargs &&
! 122: copyin((void *)args[0], argp, nargs * sizeof(int)))
! 123: bzero(argp, nargs * sizeof(int));
! 124: kth.ktr_buf = (caddr_t)ktp;
! 125: kth.ktr_len = len;
! 126: ktrwrite(p, &kth);
! 127: free(ktp, M_TEMP);
! 128: p->p_traceflag &= ~KTRFAC_ACTIVE;
! 129: }
! 130:
! 131: void
! 132: ktrsysret(struct proc *p, register_t code, int error, register_t retval)
! 133: {
! 134: struct ktr_header kth;
! 135: struct ktr_sysret ktp;
! 136:
! 137: p->p_traceflag |= KTRFAC_ACTIVE;
! 138: ktrinitheader(&kth, p, KTR_SYSRET);
! 139: ktp.ktr_code = code;
! 140: ktp.ktr_error = error;
! 141: ktp.ktr_retval = retval; /* what about val2 ? */
! 142:
! 143: kth.ktr_buf = (caddr_t)&ktp;
! 144: kth.ktr_len = sizeof(struct ktr_sysret);
! 145:
! 146: ktrwrite(p, &kth);
! 147: p->p_traceflag &= ~KTRFAC_ACTIVE;
! 148: }
! 149:
! 150: void
! 151: ktrnamei(struct proc *p, char *path)
! 152: {
! 153: struct ktr_header kth;
! 154:
! 155: p->p_traceflag |= KTRFAC_ACTIVE;
! 156: ktrinitheader(&kth, p, KTR_NAMEI);
! 157: kth.ktr_len = strlen(path);
! 158: kth.ktr_buf = path;
! 159:
! 160: ktrwrite(p, &kth);
! 161: p->p_traceflag &= ~KTRFAC_ACTIVE;
! 162: }
! 163:
! 164: void
! 165: ktremul(struct proc *p, 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(struct proc *p, int fd, enum uio_rw rw, struct iovec *iov, int len,
! 180: int error)
! 181: {
! 182: struct ktr_header kth;
! 183: struct ktr_genio *ktp;
! 184: caddr_t cp;
! 185: int resid = len, count;
! 186: int buflen;
! 187:
! 188: if (error)
! 189: return;
! 190:
! 191: p->p_traceflag |= KTRFAC_ACTIVE;
! 192:
! 193: buflen = min(PAGE_SIZE, len + sizeof(struct ktr_genio));
! 194:
! 195: ktrinitheader(&kth, p, KTR_GENIO);
! 196: ktp = malloc(buflen, M_TEMP, M_WAITOK);
! 197: ktp->ktr_fd = fd;
! 198: ktp->ktr_rw = rw;
! 199:
! 200: kth.ktr_buf = (caddr_t)ktp;
! 201:
! 202: cp = (caddr_t)((char *)ktp + sizeof (struct ktr_genio));
! 203: buflen -= sizeof(struct ktr_genio);
! 204:
! 205: while (resid > 0) {
! 206: /*
! 207: * Don't allow this process to hog the cpu when doing
! 208: * huge I/O.
! 209: */
! 210: if (curcpu()->ci_schedstate.spc_schedflags & SPCF_SHOULDYIELD)
! 211: preempt(NULL);
! 212:
! 213: count = min(iov->iov_len, buflen);
! 214: if (count > resid)
! 215: count = resid;
! 216: if (copyin(iov->iov_base, cp, count))
! 217: break;
! 218:
! 219: kth.ktr_len = count + sizeof(struct ktr_genio);
! 220:
! 221: if (ktrwrite(p, &kth) != 0)
! 222: break;
! 223:
! 224: iov->iov_len -= count;
! 225: iov->iov_base = (caddr_t)iov->iov_base + count;
! 226:
! 227: if (iov->iov_len == 0)
! 228: iov++;
! 229:
! 230: resid -= count;
! 231: }
! 232:
! 233: free(ktp, M_TEMP);
! 234: p->p_traceflag &= ~KTRFAC_ACTIVE;
! 235:
! 236: }
! 237:
! 238: void
! 239: ktrpsig(struct proc *p, int sig, sig_t action, int mask, int code,
! 240: siginfo_t *si)
! 241: {
! 242: struct ktr_header kth;
! 243: struct ktr_psig kp;
! 244:
! 245: p->p_traceflag |= KTRFAC_ACTIVE;
! 246: ktrinitheader(&kth, p, KTR_PSIG);
! 247: kp.signo = (char)sig;
! 248: kp.action = action;
! 249: kp.mask = mask;
! 250: kp.code = code;
! 251: kp.si = *si;
! 252: kth.ktr_buf = (caddr_t)&kp;
! 253: kth.ktr_len = sizeof(struct ktr_psig);
! 254:
! 255: ktrwrite(p, &kth);
! 256: p->p_traceflag &= ~KTRFAC_ACTIVE;
! 257: }
! 258:
! 259: void
! 260: ktrcsw(struct proc *p, int out, int user)
! 261: {
! 262: struct ktr_header kth;
! 263: struct ktr_csw kc;
! 264:
! 265: p->p_traceflag |= KTRFAC_ACTIVE;
! 266: ktrinitheader(&kth, p, KTR_CSW);
! 267: kc.out = out;
! 268: kc.user = user;
! 269: kth.ktr_buf = (caddr_t)&kc;
! 270: kth.ktr_len = sizeof(struct ktr_csw);
! 271:
! 272: ktrwrite(p, &kth);
! 273: p->p_traceflag &= ~KTRFAC_ACTIVE;
! 274: }
! 275:
! 276: /* Interface and common routines */
! 277:
! 278: /*
! 279: * ktrace system call
! 280: */
! 281: /* ARGSUSED */
! 282: int
! 283: sys_ktrace(struct proc *curp, void *v, register_t *retval)
! 284: {
! 285: struct sys_ktrace_args /* {
! 286: syscallarg(const char *) fname;
! 287: syscallarg(int) ops;
! 288: syscallarg(int) facs;
! 289: syscallarg(pid_t) pid;
! 290: } */ *uap = v;
! 291: struct vnode *vp = NULL;
! 292: struct proc *p = NULL;
! 293: struct pgrp *pg;
! 294: int facs = SCARG(uap, facs) & ~((unsigned) KTRFAC_ROOT);
! 295: int ops = KTROP(SCARG(uap, ops));
! 296: int descend = SCARG(uap, ops) & KTRFLAG_DESCEND;
! 297: int ret = 0;
! 298: int error = 0;
! 299: struct nameidata nd;
! 300:
! 301: curp->p_traceflag |= KTRFAC_ACTIVE;
! 302: if (ops != KTROP_CLEAR) {
! 303: /*
! 304: * an operation which requires a file argument.
! 305: */
! 306: NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, fname),
! 307: curp);
! 308: if ((error = vn_open(&nd, FREAD|FWRITE|O_NOFOLLOW, 0)) != 0) {
! 309: curp->p_traceflag &= ~KTRFAC_ACTIVE;
! 310: return (error);
! 311: }
! 312: vp = nd.ni_vp;
! 313:
! 314: VOP_UNLOCK(vp, 0, curp);
! 315: if (vp->v_type != VREG) {
! 316: (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
! 317: curp->p_traceflag &= ~KTRFAC_ACTIVE;
! 318: return (EACCES);
! 319: }
! 320: }
! 321: /*
! 322: * Clear all uses of the tracefile
! 323: */
! 324: if (ops == KTROP_CLEARFILE) {
! 325: for (p = LIST_FIRST(&allproc); p; p = LIST_NEXT(p, p_list)) {
! 326: if (p->p_tracep == vp) {
! 327: if (ktrcanset(curp, p)) {
! 328: p->p_traceflag = 0;
! 329: ktrsettracevnode(p, NULL);
! 330: } else
! 331: error = EPERM;
! 332: }
! 333: }
! 334: goto done;
! 335: }
! 336: /*
! 337: * need something to (un)trace (XXX - why is this here?)
! 338: */
! 339: if (!facs) {
! 340: error = EINVAL;
! 341: goto done;
! 342: }
! 343: /*
! 344: * do it
! 345: */
! 346: if (SCARG(uap, pid) < 0) {
! 347: /*
! 348: * by process group
! 349: */
! 350: pg = pgfind(-SCARG(uap, pid));
! 351: if (pg == NULL) {
! 352: error = ESRCH;
! 353: goto done;
! 354: }
! 355: LIST_FOREACH(p, &pg->pg_members, p_pglist)
! 356: if (descend)
! 357: ret |= ktrsetchildren(curp, p, ops, facs, vp);
! 358: else
! 359: ret |= ktrops(curp, p, ops, facs, vp);
! 360:
! 361: } else {
! 362: /*
! 363: * by pid
! 364: */
! 365: p = pfind(SCARG(uap, pid));
! 366: if (p == NULL) {
! 367: error = ESRCH;
! 368: goto done;
! 369: }
! 370: if (descend)
! 371: ret |= ktrsetchildren(curp, p, ops, facs, vp);
! 372: else
! 373: ret |= ktrops(curp, p, ops, facs, vp);
! 374: }
! 375: if (!ret)
! 376: error = EPERM;
! 377: done:
! 378: if (vp != NULL)
! 379: (void) vn_close(vp, FWRITE, curp->p_ucred, curp);
! 380: curp->p_traceflag &= ~KTRFAC_ACTIVE;
! 381: return (error);
! 382: }
! 383:
! 384: int
! 385: ktrops(struct proc *curp, struct proc *p, int ops, int facs, struct vnode *vp)
! 386: {
! 387:
! 388: if (!ktrcanset(curp, p))
! 389: return (0);
! 390: if (ops == KTROP_SET) {
! 391: ktrsettracevnode(p, vp);
! 392: p->p_traceflag |= facs;
! 393: if (curp->p_ucred->cr_uid == 0)
! 394: p->p_traceflag |= KTRFAC_ROOT;
! 395: } else {
! 396: /* KTROP_CLEAR */
! 397: if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
! 398: /* no more tracing */
! 399: p->p_traceflag = 0;
! 400: ktrsettracevnode(p, NULL);
! 401: }
! 402: }
! 403:
! 404: /*
! 405: * Emit an emulation record, every time there is a ktrace
! 406: * change/attach request.
! 407: */
! 408: if (KTRPOINT(p, KTR_EMUL))
! 409: ktremul(p, p->p_emul->e_name);
! 410:
! 411: return (1);
! 412: }
! 413:
! 414: int
! 415: ktrsetchildren(struct proc *curp, struct proc *top, int ops, int facs,
! 416: struct vnode *vp)
! 417: {
! 418: struct proc *p;
! 419: int ret = 0;
! 420:
! 421: p = top;
! 422: for (;;) {
! 423: ret |= ktrops(curp, p, ops, facs, vp);
! 424: /*
! 425: * If this process has children, descend to them next,
! 426: * otherwise do any siblings, and if done with this level,
! 427: * follow back up the tree (but not past top).
! 428: */
! 429: if (!LIST_EMPTY(&p->p_children))
! 430: p = LIST_FIRST(&p->p_children);
! 431: else for (;;) {
! 432: if (p == top)
! 433: return (ret);
! 434: if (LIST_NEXT(p, p_sibling) != NULL) {
! 435: p = LIST_NEXT(p, p_sibling);
! 436: break;
! 437: }
! 438: p = p->p_pptr;
! 439: }
! 440: }
! 441: /*NOTREACHED*/
! 442: }
! 443:
! 444: int
! 445: ktrwrite(struct proc *p, struct ktr_header *kth)
! 446: {
! 447: struct uio auio;
! 448: struct iovec aiov[2];
! 449: int error;
! 450: struct vnode *vp = p->p_tracep;
! 451:
! 452: if (vp == NULL)
! 453: return 0;
! 454: auio.uio_iov = &aiov[0];
! 455: auio.uio_offset = 0;
! 456: auio.uio_segflg = UIO_SYSSPACE;
! 457: auio.uio_rw = UIO_WRITE;
! 458: aiov[0].iov_base = (caddr_t)kth;
! 459: aiov[0].iov_len = sizeof(struct ktr_header);
! 460: auio.uio_resid = sizeof(struct ktr_header);
! 461: auio.uio_iovcnt = 1;
! 462: auio.uio_procp = p;
! 463: if (kth->ktr_len > 0) {
! 464: auio.uio_iovcnt++;
! 465: aiov[1].iov_base = kth->ktr_buf;
! 466: aiov[1].iov_len = kth->ktr_len;
! 467: auio.uio_resid += kth->ktr_len;
! 468: }
! 469: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
! 470: error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred);
! 471: VOP_UNLOCK(vp, 0, p);
! 472: if (!error)
! 473: return 0;
! 474: /*
! 475: * If error encountered, give up tracing on this vnode.
! 476: */
! 477: log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
! 478: error);
! 479: for (p = LIST_FIRST(&allproc); p != NULL; p = LIST_NEXT(p, p_list)) {
! 480: if (p->p_tracep == vp) {
! 481: p->p_traceflag = 0;
! 482: ktrsettracevnode(p, NULL);
! 483: }
! 484: }
! 485:
! 486: return error;
! 487: }
! 488:
! 489: /*
! 490: * Return true if caller has permission to set the ktracing state
! 491: * of target. Essentially, the target can't possess any
! 492: * more permissions than the caller. KTRFAC_ROOT signifies that
! 493: * root previously set the tracing status on the target process, and
! 494: * so, only root may further change it.
! 495: *
! 496: * TODO: check groups. use caller effective gid.
! 497: */
! 498: int
! 499: ktrcanset(struct proc *callp, struct proc *targetp)
! 500: {
! 501: struct pcred *caller = callp->p_cred;
! 502: struct pcred *target = targetp->p_cred;
! 503:
! 504: if ((caller->pc_ucred->cr_uid == target->p_ruid &&
! 505: target->p_ruid == target->p_svuid &&
! 506: caller->p_rgid == target->p_rgid && /* XXX */
! 507: target->p_rgid == target->p_svgid &&
! 508: (targetp->p_traceflag & KTRFAC_ROOT) == 0 &&
! 509: !ISSET(targetp->p_flag, P_SUGID)) ||
! 510: caller->pc_ucred->cr_uid == 0)
! 511: return (1);
! 512:
! 513: return (0);
! 514: }
! 515:
! 516: #endif
CVSweb