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 /*
    2  * Copyright (c) 1989, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by the University of
   16  *      California, Berkeley and its contributors.
   17  * 4. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  *
   33  *      @(#)kern_ktrace.c       8.2 (Berkeley) 9/23/93
   34  * $FreeBSD$
   35  */
   36 
   37 #include "opt_ktrace.h"
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/sysproto.h>
   42 #include <sys/kernel.h>
   43 #include <sys/proc.h>
   44 #include <sys/fcntl.h>
   45 #include <sys/lock.h>
   46 #include <sys/namei.h>
   47 #include <sys/vnode.h>
   48 #include <sys/ktrace.h>
   49 #include <sys/malloc.h>
   50 #include <sys/sysent.h>
   51 #include <sys/syslog.h>
   52 
   53 static MALLOC_DEFINE(M_KTRACE, "KTRACE", "KTRACE");
   54 
   55 #ifdef KTRACE
   56 static struct ktr_header *ktrgetheader __P((int type));
   57 static void ktrwrite __P((struct vnode *, struct ktr_header *, struct uio *));
   58 static int ktrcanset __P((struct proc *,struct proc *));
   59 static int ktrsetchildren __P((struct proc *,struct proc *,int,int,struct vnode *));
   60 static int ktrops __P((struct proc *,struct proc *,int,int,struct vnode *));
   61 
   62 
   63 static struct ktr_header *
   64 ktrgetheader(type)
   65         int type;
   66 {
   67         register struct ktr_header *kth;
   68         struct proc *p = curproc;       /* XXX */
   69 
   70         MALLOC(kth, struct ktr_header *, sizeof (struct ktr_header),
   71                 M_KTRACE, M_WAITOK);
   72         kth->ktr_type = type;
   73         microtime(&kth->ktr_time);
   74         kth->ktr_pid = p->p_pid;
   75         bcopy(p->p_comm, kth->ktr_comm, MAXCOMLEN);
   76         return (kth);
   77 }
   78 
   79 void
   80 ktrsyscall(vp, code, narg, args)
   81         struct vnode *vp;
   82         int code, narg, args[];
   83 {
   84         struct  ktr_header *kth;
   85         struct  ktr_syscall *ktp;
   86         register int len = sizeof(struct ktr_syscall) + (narg * sizeof(int));
   87         struct proc *p = curproc;       /* XXX */
   88         int     *argp, i;
   89 
   90         p->p_traceflag |= KTRFAC_ACTIVE;
   91         kth = ktrgetheader(KTR_SYSCALL);
   92         MALLOC(ktp, struct ktr_syscall *, len, M_KTRACE, M_WAITOK);
   93         ktp->ktr_code = code;
   94         ktp->ktr_narg = narg;
   95         argp = (int *)((char *)ktp + sizeof(struct ktr_syscall));
   96         for (i = 0; i < narg; i++)
   97                 *argp++ = args[i];
   98         kth->ktr_buf = (caddr_t)ktp;
   99         kth->ktr_len = len;
  100         ktrwrite(vp, kth, NULL);
  101         FREE(ktp, M_KTRACE);
  102         FREE(kth, M_KTRACE);
  103         p->p_traceflag &= ~KTRFAC_ACTIVE;
  104 }
  105 
  106 void
  107 ktrsysret(vp, code, error, retval)
  108         struct vnode *vp;
  109         int code, error, retval;
  110 {
  111         struct ktr_header *kth;
  112         struct ktr_sysret ktp;
  113         struct proc *p = curproc;       /* XXX */
  114 
  115         p->p_traceflag |= KTRFAC_ACTIVE;
  116         kth = ktrgetheader(KTR_SYSRET);
  117         ktp.ktr_code = code;
  118         ktp.ktr_error = error;
  119         ktp.ktr_retval = retval;                /* what about val2 ? */
  120 
  121         kth->ktr_buf = (caddr_t)&ktp;
  122         kth->ktr_len = sizeof(struct ktr_sysret);
  123 
  124         ktrwrite(vp, kth, NULL);
  125         FREE(kth, M_KTRACE);
  126         p->p_traceflag &= ~KTRFAC_ACTIVE;
  127 }
  128 
  129 void
  130 ktrnamei(vp, path)
  131         struct vnode *vp;
  132         char *path;
  133 {
  134         struct ktr_header *kth;
  135         struct proc *p = curproc;       /* XXX */
  136 
  137         p->p_traceflag |= KTRFAC_ACTIVE;
  138         kth = ktrgetheader(KTR_NAMEI);
  139         kth->ktr_len = strlen(path);
  140         kth->ktr_buf = path;
  141 
  142         ktrwrite(vp, kth, NULL);
  143         FREE(kth, M_KTRACE);
  144         p->p_traceflag &= ~KTRFAC_ACTIVE;
  145 }
  146 
  147 void
  148 ktrgenio(vp, fd, rw, uio, error)
  149         struct vnode *vp;
  150         int fd;
  151         enum uio_rw rw;
  152         struct uio *uio;
  153         int error;
  154 {
  155         struct ktr_header *kth;
  156         struct ktr_genio ktg;
  157         struct proc *p = curproc;       /* XXX */
  158 
  159         if (error)
  160                 return;
  161         p->p_traceflag |= KTRFAC_ACTIVE;
  162         kth = ktrgetheader(KTR_GENIO);
  163         ktg.ktr_fd = fd;
  164         ktg.ktr_rw = rw;
  165         kth->ktr_buf = (caddr_t)&ktg;
  166         kth->ktr_len = sizeof(struct ktr_genio);
  167         uio->uio_offset = 0;
  168         uio->uio_rw = UIO_WRITE;
  169 
  170         ktrwrite(vp, kth, uio);
  171         FREE(kth, M_KTRACE);
  172         p->p_traceflag &= ~KTRFAC_ACTIVE;
  173 }
  174 
  175 void
  176 ktrpsig(vp, sig, action, mask, code)
  177         struct vnode *vp;
  178         int sig;
  179         sig_t action;
  180         int mask, code;
  181 {
  182         struct ktr_header *kth;
  183         struct ktr_psig kp;
  184         struct proc *p = curproc;       /* XXX */
  185 
  186         p->p_traceflag |= KTRFAC_ACTIVE;
  187         kth = ktrgetheader(KTR_PSIG);
  188         kp.signo = (char)sig;
  189         kp.action = action;
  190         kp.mask = mask;
  191         kp.code = code;
  192         kth->ktr_buf = (caddr_t)&kp;
  193         kth->ktr_len = sizeof (struct ktr_psig);
  194 
  195         ktrwrite(vp, kth, NULL);
  196         FREE(kth, M_KTRACE);
  197         p->p_traceflag &= ~KTRFAC_ACTIVE;
  198 }
  199 
  200 void
  201 ktrcsw(vp, out, user)
  202         struct vnode *vp;
  203         int out, user;
  204 {
  205         struct ktr_header *kth;
  206         struct  ktr_csw kc;
  207         struct proc *p = curproc;       /* XXX */
  208 
  209         p->p_traceflag |= KTRFAC_ACTIVE;
  210         kth = ktrgetheader(KTR_CSW);
  211         kc.out = out;
  212         kc.user = user;
  213         kth->ktr_buf = (caddr_t)&kc;
  214         kth->ktr_len = sizeof (struct ktr_csw);
  215 
  216         ktrwrite(vp, kth, NULL);
  217         FREE(kth, M_KTRACE);
  218         p->p_traceflag &= ~KTRFAC_ACTIVE;
  219 }
  220 #endif
  221 
  222 /* Interface and common routines */
  223 
  224 /*
  225  * ktrace system call
  226  */
  227 #ifndef _SYS_SYSPROTO_H_
  228 struct ktrace_args {
  229         char    *fname;
  230         int     ops;
  231         int     facs;
  232         int     pid;
  233 };
  234 #endif
  235 /* ARGSUSED */
  236 int
  237 ktrace(curp, uap)
  238         struct proc *curp;
  239         register struct ktrace_args *uap;
  240 {
  241 #ifdef KTRACE
  242         register struct vnode *vp = NULL;
  243         register struct proc *p;
  244         struct pgrp *pg;
  245         int facs = uap->facs & ~KTRFAC_ROOT;
  246         int ops = KTROP(uap->ops);
  247         int descend = uap->ops & KTRFLAG_DESCEND;
  248         int ret = 0;
  249         int error = 0;
  250         struct nameidata nd;
  251 
  252         curp->p_traceflag |= KTRFAC_ACTIVE;
  253         if (ops != KTROP_CLEAR) {
  254                 /*
  255                  * an operation which requires a file argument.
  256                  */
  257                 NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, curp);
  258                 error = vn_open(&nd, FREAD|FWRITE|O_NOFOLLOW, 0);
  259                 if (error) {
  260                         curp->p_traceflag &= ~KTRFAC_ACTIVE;
  261                         return (error);
  262                 }
  263                 vp = nd.ni_vp;
  264                 VOP_UNLOCK(vp, 0, curp);
  265                 if (vp->v_type != VREG) {
  266                         (void) vn_close(vp, FREAD|FWRITE, curp->p_ucred, curp);
  267                         curp->p_traceflag &= ~KTRFAC_ACTIVE;
  268                         return (EACCES);
  269                 }
  270         }
  271         /*
  272          * Clear all uses of the tracefile
  273          */
  274         if (ops == KTROP_CLEARFILE) {
  275                 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
  276                         if (p->p_tracep == vp) {
  277                                 if (ktrcanset(curp, p)) {
  278                                         p->p_tracep = NULL;
  279                                         p->p_traceflag = 0;
  280                                         (void) vn_close(vp, FREAD|FWRITE,
  281                                                 p->p_ucred, p);
  282                                 } else
  283                                         error = EPERM;
  284                         }
  285                 }
  286                 goto done;
  287         }
  288         /*
  289          * need something to (un)trace (XXX - why is this here?)
  290          */
  291         if (!facs) {
  292                 error = EINVAL;
  293                 goto done;
  294         }
  295         /*
  296          * do it
  297          */
  298         if (uap->pid < 0) {
  299                 /*
  300                  * by process group
  301                  */
  302                 pg = pgfind(-uap->pid);
  303                 if (pg == NULL) {
  304                         error = ESRCH;
  305                         goto done;
  306                 }
  307                 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next)
  308                         if (descend)
  309                                 ret |= ktrsetchildren(curp, p, ops, facs, vp);
  310                         else
  311                                 ret |= ktrops(curp, p, ops, facs, vp);
  312 
  313         } else {
  314                 /*
  315                  * by pid
  316                  */
  317                 p = pfind(uap->pid);
  318                 if (p == NULL) {
  319                         error = ESRCH;
  320                         goto done;
  321                 }
  322                 if (descend)
  323                         ret |= ktrsetchildren(curp, p, ops, facs, vp);
  324                 else
  325                         ret |= ktrops(curp, p, ops, facs, vp);
  326         }
  327         if (!ret)
  328                 error = EPERM;
  329 done:
  330         if (vp != NULL)
  331                 (void) vn_close(vp, FWRITE, curp->p_ucred, curp);
  332         curp->p_traceflag &= ~KTRFAC_ACTIVE;
  333         return (error);
  334 #else
  335         return ENOSYS;
  336 #endif
  337 }
  338 
  339 /*
  340  * utrace system call
  341  */
  342 /* ARGSUSED */
  343 int
  344 utrace(curp, uap)
  345         struct proc *curp;
  346         register struct utrace_args *uap;
  347 {
  348 #ifdef KTRACE
  349         struct ktr_header *kth;
  350         struct proc *p = curproc;       /* XXX */
  351         register caddr_t cp;
  352 
  353         if (!KTRPOINT(p, KTR_USER))
  354                 return (0);
  355         if (SCARG(uap, len) > KTR_USER_MAXLEN)
  356                 return (EINVAL);
  357         p->p_traceflag |= KTRFAC_ACTIVE;
  358         kth = ktrgetheader(KTR_USER);
  359         MALLOC(cp, caddr_t, uap->len, M_KTRACE, M_WAITOK);
  360         if (!copyin(uap->addr, cp, uap->len)) {
  361                 kth->ktr_buf = cp;
  362                 kth->ktr_len = uap->len;
  363                 ktrwrite(p->p_tracep, kth, NULL);
  364         }
  365         FREE(kth, M_KTRACE);
  366         FREE(cp, M_KTRACE);
  367         p->p_traceflag &= ~KTRFAC_ACTIVE;
  368 
  369         return (0);
  370 #else
  371         return (ENOSYS);
  372 #endif
  373 }
  374 
  375 #ifdef KTRACE
  376 static int
  377 ktrops(curp, p, ops, facs, vp)
  378         struct proc *p, *curp;
  379         int ops, facs;
  380         struct vnode *vp;
  381 {
  382 
  383         if (!ktrcanset(curp, p))
  384                 return (0);
  385         if (ops == KTROP_SET) {
  386                 if (p->p_tracep != vp) {
  387                         /*
  388                          * if trace file already in use, relinquish
  389                          */
  390                         if (p->p_tracep != NULL)
  391                                 vrele(p->p_tracep);
  392                         VREF(vp);
  393                         p->p_tracep = vp;
  394                 }
  395                 p->p_traceflag |= facs;
  396                 if (curp->p_ucred->cr_uid == 0)
  397                         p->p_traceflag |= KTRFAC_ROOT;
  398         } else {
  399                 /* KTROP_CLEAR */
  400                 if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
  401                         /* no more tracing */
  402                         p->p_traceflag = 0;
  403                         if (p->p_tracep != NULL) {
  404                                 vrele(p->p_tracep);
  405                                 p->p_tracep = NULL;
  406                         }
  407                 }
  408         }
  409 
  410         return (1);
  411 }
  412 
  413 static int
  414 ktrsetchildren(curp, top, ops, facs, vp)
  415         struct proc *curp, *top;
  416         int ops, facs;
  417         struct vnode *vp;
  418 {
  419         register struct proc *p;
  420         register int ret = 0;
  421 
  422         p = top;
  423         for (;;) {
  424                 ret |= ktrops(curp, p, ops, facs, vp);
  425                 /*
  426                  * If this process has children, descend to them next,
  427                  * otherwise do any siblings, and if done with this level,
  428                  * follow back up the tree (but not past top).
  429                  */
  430                 if (p->p_children.lh_first)
  431                         p = p->p_children.lh_first;
  432                 else for (;;) {
  433                         if (p == top)
  434                                 return (ret);
  435                         if (p->p_sibling.le_next) {
  436                                 p = p->p_sibling.le_next;
  437                                 break;
  438                         }
  439                         p = p->p_pptr;
  440                 }
  441         }
  442         /*NOTREACHED*/
  443 }
  444 
  445 static void
  446 ktrwrite(vp, kth, uio)
  447         struct vnode *vp;
  448         register struct ktr_header *kth;
  449         struct uio *uio;
  450 {
  451         struct uio auio;
  452         struct iovec aiov[2];
  453         register struct proc *p = curproc;      /* XXX */
  454         int error;
  455 
  456         if (vp == NULL)
  457                 return;
  458         auio.uio_iov = &aiov[0];
  459         auio.uio_offset = 0;
  460         auio.uio_segflg = UIO_SYSSPACE;
  461         auio.uio_rw = UIO_WRITE;
  462         aiov[0].iov_base = (caddr_t)kth;
  463         aiov[0].iov_len = sizeof(struct ktr_header);
  464         auio.uio_resid = sizeof(struct ktr_header);
  465         auio.uio_iovcnt = 1;
  466         auio.uio_procp = curproc;
  467         if (kth->ktr_len > 0) {
  468                 auio.uio_iovcnt++;
  469                 aiov[1].iov_base = kth->ktr_buf;
  470                 aiov[1].iov_len = kth->ktr_len;
  471                 auio.uio_resid += kth->ktr_len;
  472                 if (uio != NULL)
  473                         kth->ktr_len += uio->uio_resid;
  474         }
  475         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  476         (void)VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
  477         error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, p->p_ucred);
  478         if (error == 0 && uio != NULL) {
  479                 (void)VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
  480                 error = VOP_WRITE(vp, uio, IO_UNIT | IO_APPEND, p->p_ucred);
  481         }
  482         VOP_UNLOCK(vp, 0, p);
  483         if (!error)
  484                 return;
  485         /*
  486          * If error encountered, give up tracing on this vnode.
  487          */
  488         log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
  489             error);
  490         for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
  491                 if (p->p_tracep == vp) {
  492                         p->p_tracep = NULL;
  493                         p->p_traceflag = 0;
  494                         vrele(vp);
  495                 }
  496         }
  497 }
  498 
  499 /*
  500  * Return true if caller has permission to set the ktracing state
  501  * of target.  Essentially, the target can't possess any
  502  * more permissions than the caller.  KTRFAC_ROOT signifies that
  503  * root previously set the tracing status on the target process, and
  504  * so, only root may further change it.
  505  *
  506  * TODO: check groups.  use caller effective gid.
  507  */
  508 static int
  509 ktrcanset(callp, targetp)
  510         struct proc *callp, *targetp;
  511 {
  512         register struct pcred *caller = callp->p_cred;
  513         register struct pcred *target = targetp->p_cred;
  514 
  515         if ((caller->pc_ucred->cr_uid == target->p_ruid &&
  516              target->p_ruid == target->p_svuid &&
  517              caller->p_rgid == target->p_rgid &&        /* XXX */
  518              target->p_rgid == target->p_svgid &&
  519              (targetp->p_traceflag & KTRFAC_ROOT) == 0) ||
  520              caller->pc_ucred->cr_uid == 0)
  521                 return (1);
  522 
  523         return (0);
  524 }
  525 
  526 #endif /* KTRACE */

Cache object: b50888ec992626e685c0bfe916d59960


[ 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.