[BACK]Return to kern_ktrace.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/kern_ktrace.c, Revision 1.1.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