The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_ktrace.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 1bd3fd3c19e8e4ba0160928a22846177


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.