[BACK]Return to kern_ktrace.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Annotation of src/sys/kern/kern_ktrace.c, Revision 1.90

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

CVSweb <webmaster@jp.NetBSD.org>