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_systrace.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_systrace.c,v 1.63 2006/11/28 17:58:10 elad Exp $  */
    2 
    3 /*
    4  * Copyright 2002, 2003 Niels Provos <provos@citi.umich.edu>
    5  * 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. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Niels Provos.
   18  * 4. The name of the author may not be used to endorse or promote products
   19  *    derived from this software without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: kern_systrace.c,v 1.63 2006/11/28 17:58:10 elad Exp $");
   35 
   36 #include "opt_systrace.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/tree.h>
   41 #include <sys/malloc.h>
   42 #include <sys/syscall.h>
   43 #include <sys/vnode.h>
   44 #include <sys/errno.h>
   45 #include <sys/conf.h>
   46 #include <sys/device.h>
   47 #include <sys/proc.h>
   48 #include <sys/file.h>
   49 #include <sys/filedesc.h>
   50 #include <sys/filio.h>
   51 #include <sys/signalvar.h>
   52 #include <sys/lock.h>
   53 #include <sys/pool.h>
   54 #include <sys/mount.h>
   55 #include <sys/poll.h>
   56 #include <sys/ptrace.h>
   57 #include <sys/namei.h>
   58 #include <sys/systrace.h>
   59 #include <sys/sa.h>
   60 #include <sys/savar.h>
   61 #include <sys/kauth.h>
   62 
   63 #include <compat/common/compat_util.h>
   64 
   65 #ifdef __NetBSD__
   66 #define SYSTRACE_LOCK(fst, p)   lockmgr(&fst->lock, LK_EXCLUSIVE, NULL)
   67 #define SYSTRACE_UNLOCK(fst, p) lockmgr(&fst->lock, LK_RELEASE, NULL)
   68 #else
   69 #define SYSTRACE_LOCK(fst, p)   lockmgr(&fst->lock, LK_EXCLUSIVE, NULL, p)
   70 #define SYSTRACE_UNLOCK(fst, p) lockmgr(&fst->lock, LK_RELEASE, NULL, p)
   71 #endif
   72 #ifndef M_XDATA
   73 MALLOC_DEFINE(M_SYSTR, "systrace", "systrace");
   74 #define M_XDATA         M_SYSTR
   75 #endif
   76 
   77 #ifdef __NetBSD__
   78 dev_type_open(systraceopen);
   79 #else
   80 cdev_decl(systrace);
   81 #endif
   82 
   83 #ifdef __NetBSD__
   84 int     systracef_read(struct file *, off_t *, struct uio *, kauth_cred_t,
   85                 int);
   86 int     systracef_write(struct file *, off_t *, struct uio *, kauth_cred_t,
   87                 int);
   88 int     systracef_poll(struct file *, int, struct lwp *);
   89 int     systracef_ioctl(struct file *, u_long, void *, struct lwp *);
   90 int     systracef_close(struct file *, struct lwp *);
   91 #else
   92 int     systracef_read(struct file *, off_t *, struct uio *, kauth_cred_t);
   93 int     systracef_write(struct file *, off_t *, struct uio *, kauth_cred_t);
   94 int     systracef_select(struct file *, int, struct proc *);
   95 int     systracef_ioctl(struct file *, u_long, caddr_t, struct proc *);
   96 int     systracef_stat(struct file *, struct stat *, struct proc *);
   97 int     systracef_close(struct file *, struct proc *);
   98 #endif
   99 
  100 struct str_policy {
  101         TAILQ_ENTRY(str_policy) next;
  102 
  103         int nr;
  104 
  105         const struct emul *emul;        /* Is only valid for this emulation */
  106 
  107         int refcount;
  108 
  109         int nsysent;
  110         u_char *sysent;
  111 };
  112 
  113 #define STR_PROC_ONQUEUE        0x01
  114 #define STR_PROC_WAITANSWER     0x02
  115 #define STR_PROC_SYSCALLRES     0x04
  116 #define STR_PROC_REPORT         0x08    /* Report emulation */
  117 #define STR_PROC_NEEDSEQNR      0x10    /* Answer must quote seqnr */
  118 #define STR_PROC_SETEUID        0x20    /* Elevate privileges */
  119 #define STR_PROC_SETEGID        0x40
  120 #define STR_PROC_DIDSETUGID     0x80
  121 
  122 struct str_process {
  123         TAILQ_ENTRY(str_process) next;
  124 
  125         struct proc *proc;
  126         const struct emul *oldemul;
  127         uid_t olduid;
  128         gid_t oldgid;
  129 
  130         pid_t pid;
  131 
  132         struct fsystrace *parent;
  133         struct str_policy *policy;
  134 
  135         struct systrace_replace *replace;
  136         char *fname[SYSTR_MAXFNAME];
  137         size_t nfname;
  138 
  139         int flags;
  140         short answer;
  141         short error;
  142         uint16_t seqnr;         /* expected reply sequence number */
  143 
  144         uid_t seteuid;
  145         uid_t saveuid;
  146         gid_t setegid;
  147         gid_t savegid;
  148 
  149         int isscript;
  150         char scriptname[MAXPATHLEN];
  151 };
  152 
  153 uid_t   systrace_seteuid(struct lwp *, uid_t);
  154 gid_t   systrace_setegid(struct lwp *, gid_t);
  155 void systrace_lock(void);
  156 void systrace_unlock(void);
  157 
  158 /* Needs to be called with fst locked */
  159 
  160 int     systrace_attach(struct fsystrace *, pid_t);
  161 int     systrace_detach(struct str_process *);
  162 int     systrace_answer(struct str_process *, struct systrace_answer *);
  163 int     systrace_setscriptname(struct str_process *, struct 
  164             systrace_scriptname *);
  165 int     systrace_io(struct str_process *, struct systrace_io *);
  166 int     systrace_policy(struct fsystrace *, struct systrace_policy *);
  167 int     systrace_preprepl(struct str_process *, struct systrace_replace *);
  168 int     systrace_replace(struct str_process *, size_t, register_t []);
  169 int     systrace_getcwd(struct fsystrace *, struct str_process *);
  170 int     systrace_fname(struct str_process *, caddr_t, size_t);
  171 void    systrace_replacefree(struct str_process *);
  172 
  173 int     systrace_processready(struct str_process *);
  174 struct proc *systrace_find(struct str_process *);
  175 struct str_process *systrace_findpid(struct fsystrace *fst, pid_t pid);
  176 void    systrace_wakeup(struct fsystrace *);
  177 void    systrace_closepolicy(struct fsystrace *, struct str_policy *);
  178 int     systrace_insert_process(struct fsystrace *, struct proc *,
  179             struct str_process **);
  180 struct str_policy *systrace_newpolicy(struct fsystrace *, int);
  181 int     systrace_msg_child(struct fsystrace *, struct str_process *, pid_t);
  182 int     systrace_msg_policyfree(struct fsystrace *, struct str_policy *);
  183 int     systrace_msg_ask(struct fsystrace *, struct str_process *,
  184             int, size_t, register_t []);
  185 int     systrace_msg_result(struct fsystrace *, struct str_process *,
  186             int, int, size_t, register_t [], register_t []);
  187 int     systrace_msg_emul(struct fsystrace *, struct str_process *);
  188 int     systrace_msg_ugid(struct fsystrace *, struct str_process *);
  189 int     systrace_make_msg(struct str_process *, int, struct str_message *);
  190 
  191 static const struct fileops systracefops = {
  192         systracef_read,
  193         systracef_write,
  194         systracef_ioctl,
  195         fnullop_fcntl,
  196         systracef_poll,
  197         fbadop_stat,
  198         systracef_close,
  199         fnullop_kqfilter
  200 };
  201 
  202 #ifdef __NetBSD__
  203 POOL_INIT(systr_proc_pl, sizeof(struct str_process), 0, 0, 0, "strprocpl",
  204     NULL);
  205 POOL_INIT(systr_policy_pl, sizeof(struct str_policy), 0, 0, 0, "strpolpl",
  206     NULL);
  207 POOL_INIT(systr_msgcontainer_pl, sizeof(struct str_msgcontainer), 0, 0, 0,
  208     "strmsgpl", NULL);
  209 
  210 struct lock systrace_lck = LOCK_INITIALIZER(PLOCK, "systrace", 0, 0);
  211 #else /* ! __NetBSD__ */
  212 struct pool systr_proc_pl;
  213 struct pool systr_policy_pl;
  214 struct pool systr_msgcontainer_pl;
  215 
  216 struct lock systrace_lck;
  217 #endif /* __NetBSD__ */
  218 
  219 int systrace_debug = 0;
  220 
  221 #ifdef __NetBSD__
  222 const struct cdevsw systrace_cdevsw = {
  223         systraceopen, noclose, noread, nowrite, noioctl,
  224         nostop, notty, nopoll, nommap, nokqfilter, D_OTHER,
  225 };
  226 #endif
  227 
  228 #define DPRINTF(y)      if (systrace_debug) printf y;
  229 
  230 /* ARGSUSED */
  231 int
  232 systracef_read(struct file *fp, off_t *poff, struct uio *uio, kauth_cred_t cred,
  233     int flags)
  234 {
  235         struct fsystrace *fst = (struct fsystrace *)fp->f_data;
  236         struct str_msgcontainer *cont;
  237         int error = 0;
  238 
  239         if (uio->uio_resid != sizeof(struct str_message))
  240                 return (EINVAL);
  241 
  242  again:
  243         systrace_lock();
  244         SYSTRACE_LOCK(fst, curlwp);
  245         systrace_unlock();
  246         if ((cont = TAILQ_FIRST(&fst->messages)) != NULL) {
  247                 error = uiomove((caddr_t)&cont->msg,
  248                     sizeof(struct str_message), uio);
  249                 if (!error) {
  250                         TAILQ_REMOVE(&fst->messages, cont, next);
  251                         if (!SYSTR_MSG_NOPROCESS(cont))
  252                                 CLR(cont->strp->flags, STR_PROC_ONQUEUE);
  253                         pool_put(&systr_msgcontainer_pl, cont);
  254 
  255                 }
  256         } else if (TAILQ_FIRST(&fst->processes) == NULL) {
  257                 /* EOF situation */
  258                 ;
  259         } else {
  260                 if (fp->f_flag & FNONBLOCK)
  261                         error = EAGAIN;
  262                 else {
  263                         SYSTRACE_UNLOCK(fst, curlwp);
  264                         error = tsleep(fst, PWAIT|PCATCH, "systrrd", 0);
  265                         if (error)
  266                                 goto out;
  267                         goto again;
  268                 }
  269 
  270         }
  271 
  272         SYSTRACE_UNLOCK(fst, curlwp);
  273  out:
  274         return (error);
  275 }
  276 
  277 /* ARGSUSED */
  278 int
  279 systracef_write(struct file *fp, off_t *poff, struct uio *uio,
  280     kauth_cred_t cred, int flags)
  281 {
  282 
  283         return (EIO);
  284 }
  285 
  286 #define POLICY_VALID(x) ((x) == SYSTR_POLICY_PERMIT || \
  287                          (x) == SYSTR_POLICY_ASK || \
  288                          (x) == SYSTR_POLICY_NEVER)
  289 
  290 /* ARGSUSED */
  291 int
  292 systracef_ioctl(struct file *fp, u_long cmd, void *data, struct lwp *l)
  293 {
  294         int ret = 0;
  295         struct fsystrace *fst = (struct fsystrace *)fp->f_data;
  296 #ifdef __NetBSD__
  297         struct proc *p = l->l_proc;
  298         struct cwdinfo *cwdp;
  299 #else
  300         struct filedesc *fdp;
  301 #endif
  302         struct str_process *strp = NULL;
  303         pid_t pid = 0;
  304 
  305         switch (cmd) {
  306         case FIONBIO:
  307         case FIOASYNC:
  308                 return (0);
  309 
  310         case STRIOCDETACH:
  311         case STRIOCREPORT:
  312                 pid = *(pid_t *)data;
  313                 if (!pid)
  314                         ret = EINVAL;
  315                 break;
  316         case STRIOCANSWER:
  317                 pid = ((struct systrace_answer *)data)->stra_pid;
  318                 if (!pid)
  319                         ret = EINVAL;
  320                 break;
  321         case STRIOCIO:
  322                 pid = ((struct systrace_io *)data)->strio_pid;
  323                 if (!pid)
  324                         ret = EINVAL;
  325                 break;
  326         case STRIOCSCRIPTNAME:
  327                 pid = ((struct systrace_scriptname *)data)->sn_pid;
  328                 if (!pid)
  329                         ret = EINVAL;
  330                 break;
  331         case STRIOCGETCWD:
  332                 pid = *(pid_t *)data;
  333                 if (!pid)
  334                         ret = EINVAL;
  335                 break;
  336         case STRIOCATTACH:
  337         case STRIOCRESCWD:
  338         case STRIOCPOLICY:
  339                 break;
  340         case STRIOCREPLACE:
  341                 pid = ((struct systrace_replace *)data)->strr_pid;
  342                 if (!pid)
  343                         ret = EINVAL;
  344                 break;
  345         default:
  346                 ret = EINVAL;
  347                 break;
  348         }
  349 
  350         if (ret)
  351                 return (ret);
  352 
  353         systrace_lock();
  354         SYSTRACE_LOCK(fst, curlwp);
  355         systrace_unlock();
  356         if (pid) {
  357                 strp = systrace_findpid(fst, pid);
  358                 if (strp == NULL) {
  359                         ret = ESRCH;
  360                         goto unlock;
  361                 }
  362         }
  363 
  364         switch (cmd) {
  365         case STRIOCATTACH:
  366                 pid = *(pid_t *)data;
  367                 if (!pid)
  368                         ret = EINVAL;
  369                 else
  370                         ret = systrace_attach(fst, pid);
  371                 DPRINTF(("%s: attach to %u: %d\n", __func__, pid, ret));
  372                 break;
  373         case STRIOCDETACH:
  374                 ret = systrace_detach(strp);
  375                 break;
  376         case STRIOCREPORT:
  377                 SET(strp->flags, STR_PROC_REPORT);
  378                 break;
  379         case STRIOCANSWER:
  380                 ret = systrace_answer(strp, (struct systrace_answer *)data);
  381                 break;
  382         case STRIOCIO:
  383                 ret = systrace_io(strp, (struct systrace_io *)data);
  384                 break;
  385         case STRIOCSCRIPTNAME:
  386                 ret = systrace_setscriptname(strp,
  387                     (struct systrace_scriptname *)data);
  388                 break;
  389         case STRIOCPOLICY:
  390                 ret = systrace_policy(fst, (struct systrace_policy *)data);
  391                 break;
  392         case STRIOCREPLACE:
  393                 ret = systrace_preprepl(strp, (struct systrace_replace *)data);
  394                 break;
  395         case STRIOCRESCWD:
  396                 if (!fst->fd_pid) {
  397                         ret = EINVAL;
  398                         break;
  399                 }
  400 #ifdef __NetBSD__
  401                 cwdp = p->p_cwdi;
  402 
  403                 /* Release cwd from other process */
  404                 if (cwdp->cwdi_cdir)
  405                         vrele(cwdp->cwdi_cdir);
  406                 if (cwdp->cwdi_rdir)
  407                         vrele(cwdp->cwdi_rdir);
  408                 cwdp->cwdi_cdir = fst->fd_cdir;
  409                 cwdp->cwdi_rdir = fst->fd_rdir;
  410 #else
  411                 fdp = p->p_fd;
  412 
  413                 /* Release cwd from other process */
  414                 if (fdp->fd_cdir)
  415                         vrele(fdp->fd_cdir);
  416                 if (fdp->fd_rdir)
  417                         vrele(fdp->fd_rdir);
  418                 /* This restores the cwd we had before */
  419                 fdp->fd_cdir = fst->fd_cdir;
  420                 fdp->fd_rdir = fst->fd_rdir;
  421 #endif
  422                 /* Note that we are normal again */
  423                 fst->fd_pid = 0;
  424                 fst->fd_cdir = fst->fd_rdir = NULL;
  425                 break;
  426         case STRIOCGETCWD:
  427                 ret = systrace_getcwd(fst, strp);
  428                 break;
  429         default:
  430                 ret = EINVAL;
  431                 break;
  432         }
  433 
  434  unlock:
  435         SYSTRACE_UNLOCK(fst, curlwp);
  436 
  437         return (ret);
  438 }
  439 
  440 #ifdef __NetBSD__
  441 int
  442 systracef_poll(struct file *fp, int events, struct lwp *l)
  443 {
  444         struct fsystrace *fst = (struct fsystrace *)fp->f_data;
  445         int revents = 0;
  446 
  447         if ((events & (POLLIN | POLLRDNORM)) == 0)
  448                 return (revents);
  449 
  450         systrace_lock();
  451         SYSTRACE_LOCK(fst, l->l_proc);
  452         systrace_unlock();
  453         if (!TAILQ_EMPTY(&fst->messages))
  454                 revents |= events & (POLLIN | POLLRDNORM);
  455         if (revents == 0)
  456                 selrecord(l, &fst->si);
  457         SYSTRACE_UNLOCK(fst, l->l_proc);
  458 
  459         return (revents);
  460 }
  461 #else
  462 int
  463 systracef_select(struct file *fp, int which, struct proc *p)
  464 {
  465         struct fsystrace *fst = (struct fsystrace *)fp->f_data;
  466         int ready = 0;
  467 
  468         if (which != FREAD)
  469                 return (0);
  470 
  471         systrace_lock();
  472         SYSTRACE_LOCK(fst, p);
  473         systrace_unlock();
  474         ready = TAILQ_FIRST(&fst->messages) != NULL;
  475         if (!ready)
  476                 selrecord(p, &fst->si);
  477         SYSTRACE_UNLOCK(fst, p);
  478 
  479         return (ready);
  480 }
  481 #endif /* __NetBSD__ */
  482 
  483 /* ARGSUSED */
  484 int
  485 systracef_close(struct file *fp, struct lwp *l)
  486 {
  487         struct fsystrace *fst = (struct fsystrace *)fp->f_data;
  488         struct str_process *strp;
  489         struct str_msgcontainer *cont;
  490         struct str_policy *strpol;
  491 
  492         systrace_lock();
  493         SYSTRACE_LOCK(fst, curlwp);
  494         systrace_unlock();
  495 
  496         /* Untrace all processes */
  497         for (strp = TAILQ_FIRST(&fst->processes); strp;
  498             strp = TAILQ_FIRST(&fst->processes)) {
  499                 struct proc *q = strp->proc;
  500 
  501                 systrace_detach(strp);
  502                 psignal(q, SIGKILL);
  503         }
  504 
  505         /* Clean up fork and exit messages */
  506         for (cont = TAILQ_FIRST(&fst->messages); cont;
  507             cont = TAILQ_FIRST(&fst->messages)) {
  508                 TAILQ_REMOVE(&fst->messages, cont, next);
  509                 pool_put(&systr_msgcontainer_pl, cont);
  510         }
  511 
  512         /* Clean up all policies */
  513         for (strpol = TAILQ_FIRST(&fst->policies); strpol;
  514             strpol = TAILQ_FIRST(&fst->policies))
  515                 systrace_closepolicy(fst, strpol);
  516 
  517         /* Release vnodes */
  518         if (fst->fd_cdir)
  519                 vrele(fst->fd_cdir);
  520         if (fst->fd_rdir)
  521                 vrele(fst->fd_rdir);
  522         SYSTRACE_UNLOCK(fst, curlwp);
  523 
  524         FREE(fp->f_data, M_XDATA);
  525         fp->f_data = NULL;
  526 
  527         return (0);
  528 }
  529 
  530 void
  531 systrace_lock(void)
  532 {
  533 #ifdef __NetBSD__
  534         lockmgr(&systrace_lck, LK_EXCLUSIVE, NULL);
  535 #else
  536         lockmgr(&systrace_lck, LK_EXCLUSIVE, NULL, curlwp);
  537 #endif
  538 }
  539 
  540 void
  541 systrace_unlock(void)
  542 {
  543 #ifdef __NetBSD__
  544         lockmgr(&systrace_lck, LK_RELEASE, NULL);
  545 #else
  546         lockmgr(&systrace_lck, LK_RELEASE, NULL, curlwp);
  547 #endif
  548 }
  549 
  550 #ifndef __NetBSD__
  551 void
  552 systrace_init(void)
  553 {
  554 
  555         pool_init(&systr_proc_pl, sizeof(struct str_process), 0, 0, 0,
  556             "strprocpl", NULL);
  557         pool_init(&systr_policy_pl, sizeof(struct str_policy), 0, 0, 0,
  558             "strpolpl", NULL);
  559         pool_init(&systr_msgcontainer_pl, sizeof(struct str_msgcontainer),
  560             0, 0, 0, "strmsgpl", NULL);
  561 
  562         lockinit(&systrace_lck, PLOCK, "systrace", 0, 0);
  563 }
  564 #endif /* ! __NetBSD__ */
  565 
  566 int
  567 systraceopen(dev_t dev, int flag, int mode, struct lwp *l)
  568 {
  569         struct fsystrace *fst;
  570         struct file *fp;
  571         int error, fd;
  572 
  573         /* falloc() will use the descriptor for us. */
  574         if ((error = falloc(l, &fp, &fd)) != 0)
  575                 return (error);
  576 
  577         MALLOC(fst, struct fsystrace *, sizeof(*fst), M_XDATA, M_WAITOK);
  578 
  579         memset(fst, 0, sizeof(struct fsystrace));
  580         lockinit(&fst->lock, PLOCK, "systrace", 0, 0);
  581 
  582         TAILQ_INIT(&fst->processes);
  583         TAILQ_INIT(&fst->messages);
  584         TAILQ_INIT(&fst->policies);
  585 
  586         if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
  587             &l->l_acflag) == 0)
  588                 fst->issuser = 1;
  589         fst->p_ruid = kauth_cred_getuid(l->l_cred);
  590         fst->p_rgid = kauth_cred_getgid(l->l_cred);
  591 
  592         return fdclone(l, fp, fd, flag, &systracefops, fst);
  593 }
  594 
  595 void
  596 systrace_wakeup(struct fsystrace *fst)
  597 {
  598         wakeup((caddr_t)fst);
  599         selwakeup(&fst->si);
  600 }
  601 
  602 struct proc *
  603 systrace_find(struct str_process *strp)
  604 {
  605         struct proc *proc;
  606 
  607         if ((proc = pfind(strp->pid)) == NULL)
  608                 return (NULL);
  609 
  610         if (proc != strp->proc)
  611                 return (NULL);
  612 
  613         if (!ISSET(proc->p_flag, P_SYSTRACE))
  614                 return (NULL);
  615 
  616         return (proc);
  617 }
  618 
  619 void
  620 systrace_sys_exit(struct proc *proc)
  621 {
  622         struct str_process *strp;
  623         struct fsystrace *fst;
  624 
  625         systrace_lock();
  626         strp = proc->p_systrace;
  627         if (strp != NULL) {
  628                 fst = strp->parent;
  629                 SYSTRACE_LOCK(fst, curlwp);
  630                 systrace_unlock();
  631 
  632                 /* Insert Exit message */
  633                 systrace_msg_child(fst, strp, -1);
  634 
  635                 systrace_detach(strp);
  636                 SYSTRACE_UNLOCK(fst, curlwp);
  637         } else
  638                 systrace_unlock();
  639         CLR(proc->p_flag, P_SYSTRACE);
  640 }
  641 
  642 void
  643 systrace_sys_fork(struct proc *oldproc, struct proc *p)
  644 {
  645         struct str_process *oldstrp, *strp;
  646         struct fsystrace *fst;
  647 
  648         systrace_lock();
  649         oldstrp = oldproc->p_systrace;
  650         if (oldstrp == NULL) {
  651                 systrace_unlock();
  652                 return;
  653         }
  654 
  655         fst = oldstrp->parent;
  656         SYSTRACE_LOCK(fst, curlwp);
  657         systrace_unlock();
  658 
  659         if (systrace_insert_process(fst, p, &strp)) {
  660                 /* We need to kill the child */
  661                 psignal(p, SIGKILL);
  662                 goto out;
  663         }
  664 
  665         /* Reference policy */
  666         if ((strp->policy = oldstrp->policy) != NULL)
  667                 strp->policy->refcount++;
  668 
  669         /* Insert fork message */
  670         systrace_msg_child(fst, oldstrp, p->p_pid);
  671  out:
  672         SYSTRACE_UNLOCK(fst, curlwp);
  673 }
  674 
  675 int
  676 systrace_enter(struct lwp *l, register_t code, void *v)
  677 {
  678         const struct sysent *callp;
  679         struct str_process *strp;
  680         struct str_policy *strpolicy;
  681         struct fsystrace *fst;
  682         struct proc *p = l->l_proc;
  683         kauth_cred_t pc;
  684         int policy, error = 0, maycontrol = 0, issuser = 0;
  685         size_t argsize;
  686 
  687         systrace_lock();
  688         strp = p->p_systrace;
  689         if (strp == NULL) {
  690                 systrace_unlock();
  691                 return (EINVAL);
  692         }
  693 
  694         KASSERT(strp->proc == p);
  695 
  696         fst = strp->parent;
  697 
  698         SYSTRACE_LOCK(fst, p);
  699         systrace_unlock();
  700 
  701         /*
  702          * We can not monitor a SUID process unless we are root,
  703          * but we wait until it executes something unprivileged.
  704          * A non-root user may only monitor if the real uid and
  705          * real gid match the monitored process.  Changing the
  706          * uid or gid causes P_SUGID to be set.
  707          */
  708         if (fst->issuser) {
  709                 maycontrol = 1;
  710                 issuser = 1;
  711         } else if (!(p->p_flag & P_SUGID)) {
  712                 maycontrol = fst->p_ruid == kauth_cred_getuid(p->p_cred) &&
  713                     fst->p_rgid == kauth_cred_getgid(p->p_cred);
  714         }
  715 
  716         if (!maycontrol) {
  717                 policy = SYSTR_POLICY_PERMIT;
  718         } else {
  719                 /* Find out current policy */
  720                 if ((strpolicy = strp->policy) == NULL)
  721                         policy = SYSTR_POLICY_ASK;
  722                 else {
  723                         if (code >= strpolicy->nsysent)
  724                                 policy = SYSTR_POLICY_NEVER;
  725                         else
  726                                 policy = strpolicy->sysent[code];
  727                 }
  728         }
  729 
  730         callp = p->p_emul->e_sysent + code;
  731 
  732         /* Fast-path */
  733         if (policy != SYSTR_POLICY_ASK) {
  734                 if (policy != SYSTR_POLICY_PERMIT) {
  735                         if (policy > 0)
  736                                 error = policy;
  737                         else
  738                                 error = EPERM;
  739                 }
  740                 strp->oldemul = NULL;
  741                 systrace_replacefree(strp);
  742                 SYSTRACE_UNLOCK(fst, p);
  743                 return (error);
  744         }
  745 
  746         /* Get the (adjusted) argsize */
  747         argsize = callp->sy_argsize;
  748 #ifdef _LP64
  749         if (p->p_flag & P_32)
  750                 argsize = argsize << 1;
  751 #endif
  752 
  753         /* Puts the current process to sleep, return unlocked */
  754         error = systrace_msg_ask(fst, strp, code, argsize, v);
  755 
  756         /* lock has been released in systrace_msg_ask() */
  757         fst = NULL;
  758         /* We might have detached by now for some reason */
  759         if (!error && (strp = p->p_systrace) != NULL) {
  760                 /* XXX - do I need to lock here? */
  761                 if (strp->answer == SYSTR_POLICY_NEVER) {
  762                         error = strp->error;
  763                         systrace_replacefree(strp);
  764                 } else {
  765                         if (ISSET(strp->flags, STR_PROC_SYSCALLRES)) {
  766 #ifndef __NetBSD__
  767                                 CLR(strp->flags, STR_PROC_SYSCALLRES);
  768 #endif
  769                         }
  770                         /* Replace the arguments if necessary */
  771                         if (strp->replace != NULL) {
  772                                 error = systrace_replace(strp, argsize, v);
  773                         }
  774                 }
  775         }
  776 
  777         systrace_lock();
  778         if ((strp = p->p_systrace) == NULL)
  779                 goto out;
  780 
  781         if (error) {
  782                 strp->oldemul = NULL;
  783                 goto out;
  784         }
  785 
  786         pc = p->p_cred;
  787         strp->oldemul = p->p_emul;
  788         strp->olduid = kauth_cred_getuid(pc);
  789         strp->oldgid = kauth_cred_getgid(pc);
  790 
  791         /* Elevate privileges as desired */
  792         if (issuser) {
  793                 if (ISSET(strp->flags, STR_PROC_SETEUID)) {
  794                         strp->saveuid = systrace_seteuid(l, strp->seteuid);
  795                         SET(strp->flags, STR_PROC_DIDSETUGID);
  796                 }
  797                 if (ISSET(strp->flags, STR_PROC_SETEGID)) {
  798                         strp->savegid = systrace_setegid(l, strp->setegid);
  799                         SET(strp->flags, STR_PROC_DIDSETUGID);
  800                 }
  801         } else
  802                 CLR(strp->flags,
  803                     STR_PROC_SETEUID|STR_PROC_SETEGID|STR_PROC_DIDSETUGID);
  804 
  805  out:
  806         systrace_unlock();
  807         return (error);
  808 }
  809 
  810 void
  811 systrace_exit(struct lwp *l, register_t code, void *v, register_t retval[],
  812     int error)
  813 {
  814         const struct sysent *callp;
  815         struct str_process *strp;
  816         struct fsystrace *fst;
  817         struct proc *p = l->l_proc;
  818         kauth_cred_t pc;
  819 
  820         /* Report change in emulation */
  821         systrace_lock();
  822         strp = p->p_systrace;
  823         if (strp == NULL || strp->oldemul == NULL) {
  824                 systrace_unlock();
  825                 return;
  826         }
  827         DPRINTF(("exit syscall %lu, oldemul %p\n", (u_long)code, strp->oldemul));
  828 
  829         /* Return to old privileges */
  830         pc = p->p_cred;
  831         if (ISSET(strp->flags, STR_PROC_DIDSETUGID)) {
  832                 if (ISSET(strp->flags, STR_PROC_SETEUID)) {
  833                         if (kauth_cred_geteuid(pc) == strp->seteuid)
  834                                 systrace_seteuid(l, strp->saveuid);
  835                 }
  836                 if (ISSET(strp->flags, STR_PROC_SETEGID)) {
  837                         if (kauth_cred_getegid(pc) == strp->setegid)
  838                                 systrace_setegid(l, strp->savegid);
  839                 }
  840         }
  841         CLR(strp->flags,
  842             STR_PROC_SETEUID|STR_PROC_SETEGID|STR_PROC_DIDSETUGID);
  843 
  844         systrace_replacefree(strp);
  845 
  846         if (p->p_flag & P_SUGID) {
  847                 if ((fst = strp->parent) == NULL || !fst->issuser) {
  848                         systrace_unlock();
  849                         return;
  850                 }
  851         }
  852 
  853         /* See if we should force a report */
  854         if (ISSET(strp->flags, STR_PROC_REPORT)) {
  855                 CLR(strp->flags, STR_PROC_REPORT);
  856                 strp->oldemul = NULL;
  857         }
  858 
  859         if (p->p_emul != strp->oldemul && strp != NULL) {
  860                 fst = strp->parent;
  861                 SYSTRACE_LOCK(fst, p);
  862                 systrace_unlock();
  863 
  864                 /* Old policy is without meaning now */
  865                 if (strp->policy) {
  866                         systrace_closepolicy(fst, strp->policy);
  867                         strp->policy = NULL;
  868                 }
  869                 systrace_msg_emul(fst, strp);
  870         } else
  871                 systrace_unlock();
  872 
  873         /* Report if effective uid or gid changed */
  874         systrace_lock();
  875         strp = p->p_systrace;
  876         if (strp != NULL && (strp->olduid != kauth_cred_getuid(p->p_cred) ||
  877             strp->oldgid != kauth_cred_getgid(p->p_cred))) {
  878 
  879                 fst = strp->parent;
  880                 SYSTRACE_LOCK(fst, p);
  881                 systrace_unlock();
  882 
  883                 systrace_msg_ugid(fst, strp);
  884         } else
  885                 systrace_unlock();
  886 
  887         /* Report result from system call */
  888         systrace_lock();
  889         strp = p->p_systrace;
  890         if (strp != NULL && ISSET(strp->flags, STR_PROC_SYSCALLRES)) {
  891                 size_t argsize;
  892 
  893                 CLR(strp->flags, STR_PROC_SYSCALLRES);
  894                 fst = strp->parent;
  895                 SYSTRACE_LOCK(fst, p);
  896                 systrace_unlock();
  897                 DPRINTF(("will ask syscall %lu, strp %p\n", (u_long)code, strp));
  898 
  899                 /* Get the (adjusted) argsize */
  900                 callp = p->p_emul->e_sysent + code;
  901                 argsize = callp->sy_argsize;
  902 #ifdef _LP64
  903                 if (p->p_flag & P_32)
  904                         argsize = argsize << 1;
  905 #endif
  906 
  907                 systrace_msg_result(fst, strp, error, code, argsize, v, retval);
  908         } else {
  909                 DPRINTF(("will not ask syscall %lu, strp %p\n", (u_long)code, strp));
  910                 systrace_unlock();
  911         }
  912 }
  913 
  914 uid_t
  915 systrace_seteuid(struct lwp *l, uid_t euid)
  916 {
  917         struct proc *p = l->l_proc;
  918         kauth_cred_t cred;
  919         uid_t oeuid;
  920 
  921         proc_crmod_enter(p);
  922         cred = p->p_cred;
  923 
  924         oeuid = kauth_cred_geteuid(cred);
  925         if (oeuid == euid) {
  926                 proc_crmod_leave(p, cred, NULL);
  927                 return (oeuid);
  928         }
  929 
  930         /* Copy credentials so other references do not see our changes. */
  931         cred = kauth_cred_dup(cred);
  932         kauth_cred_seteuid(cred, euid);
  933 
  934         /* Mark process as having changed credentials, stops tracing etc */
  935         p_sugid(p);
  936 
  937         /* Broadcast our credentials to the process and other LWPs. */
  938         proc_crmod_leave(p, cred, p->p_cred);
  939 
  940         /* Update our copy of the credentials. */
  941         lwp_update_creds(l);
  942 
  943         return (oeuid);
  944 }
  945 
  946 gid_t
  947 systrace_setegid(struct lwp *l, gid_t egid)
  948 {
  949         struct proc *p = l->l_proc;
  950         kauth_cred_t cred;
  951         gid_t oegid;
  952 
  953         proc_crmod_enter(p);
  954         cred = p->p_cred;
  955 
  956         oegid = kauth_cred_getegid(cred);
  957         if (oegid == egid) {
  958                 proc_crmod_leave(p, cred, NULL);
  959                 return (oegid);
  960         }
  961 
  962         /* Copy credentials so other references do not see our changes. */
  963         cred = kauth_cred_dup(cred);
  964         kauth_cred_setegid(cred, egid);
  965 
  966         /* Mark process as having changed credentials, stops tracing etc */
  967         p_sugid(p);
  968 
  969         /* Broadcast our credentials to the process and other LWPs. */
  970         proc_crmod_leave(p, cred, p->p_cred);
  971 
  972         /* Update our copy of the credentials. */
  973         lwp_update_creds(l);
  974 
  975         return (oegid);
  976 }
  977 
  978 /* Called with fst locked */
  979 
  980 int
  981 systrace_answer(struct str_process *strp, struct systrace_answer *ans)
  982 {
  983         int error = 0;
  984 
  985         DPRINTF(("%s: %u: policy %d\n", __func__,
  986             ans->stra_pid, ans->stra_policy));
  987 
  988         if (!POLICY_VALID(ans->stra_policy)) {
  989                 error = EINVAL;
  990                 goto out;
  991         }
  992 
  993         /* Check if answer is in sync with us */
  994         if (ans->stra_seqnr != strp->seqnr) {
  995                 error = ESRCH;
  996                 goto out;
  997         }
  998 
  999         if ((error = systrace_processready(strp)) != 0)
 1000                 goto out;
 1001 
 1002         strp->answer = ans->stra_policy;
 1003         strp->error = ans->stra_error;
 1004         if (!strp->error)
 1005                 strp->error = EPERM;
 1006         if (ISSET(ans->stra_flags, SYSTR_FLAGS_RESULT))
 1007                 SET(strp->flags, STR_PROC_SYSCALLRES);
 1008 
 1009         /* See if we should elevate privileges for this system call */
 1010         if (ISSET(ans->stra_flags, SYSTR_FLAGS_SETEUID)) {
 1011                 SET(strp->flags, STR_PROC_SETEUID);
 1012                 strp->seteuid = ans->stra_seteuid;
 1013         }
 1014         if (ISSET(ans->stra_flags, SYSTR_FLAGS_SETEGID)) {
 1015                 SET(strp->flags, STR_PROC_SETEGID);
 1016                 strp->setegid = ans->stra_setegid;
 1017         }
 1018 
 1019 
 1020         /* Clearing the flag indicates to the process that it woke up */
 1021         CLR(strp->flags, STR_PROC_WAITANSWER);
 1022         wakeup(strp);
 1023  out:
 1024 
 1025         return (error);
 1026 }
 1027 
 1028 int
 1029 systrace_setscriptname(struct str_process *strp,
 1030     struct systrace_scriptname *ans)
 1031 {
 1032         strlcpy(strp->scriptname, ans->sn_scriptname,
 1033                 sizeof(strp->scriptname));
 1034 
 1035         return (0);
 1036 }
 1037 
 1038 int
 1039 systrace_policy(struct fsystrace *fst, struct systrace_policy *pol)
 1040 {
 1041         struct str_policy *strpol;
 1042         struct str_process *strp;
 1043 
 1044         switch(pol->strp_op) {
 1045         case SYSTR_POLICY_NEW:
 1046                 DPRINTF(("%s: new, ents %d\n", __func__,
 1047                             pol->strp_maxents));
 1048                 if (pol->strp_maxents <= 0 || pol->strp_maxents > 1024)
 1049                         return (EINVAL);
 1050                 strpol = systrace_newpolicy(fst, pol->strp_maxents);
 1051                 if (strpol == NULL)
 1052                         return (ENOBUFS);
 1053                 pol->strp_num = strpol->nr;
 1054                 break;
 1055         case SYSTR_POLICY_ASSIGN:
 1056                 DPRINTF(("%s: %d -> pid %d\n", __func__,
 1057                             pol->strp_num, pol->strp_pid));
 1058 
 1059                 /* Find right policy by number */
 1060                 TAILQ_FOREACH(strpol, &fst->policies, next)
 1061                     if (strpol->nr == pol->strp_num)
 1062                             break;
 1063                 if (strpol == NULL)
 1064                         return (EINVAL);
 1065 
 1066                 strp = systrace_findpid(fst, pol->strp_pid);
 1067                 if (strp == NULL)
 1068                         return (EINVAL);
 1069 
 1070                 /* Check that emulation matches */
 1071                 if (strpol->emul && strpol->emul != strp->proc->p_emul)
 1072                         return (EINVAL);
 1073 
 1074                 if (strp->policy)
 1075                         systrace_closepolicy(fst, strp->policy);
 1076                 strp->policy = strpol;
 1077                 strpol->refcount++;
 1078 
 1079                 /* Record emulation for this policy */
 1080                 if (strpol->emul == NULL)
 1081                         strpol->emul = strp->proc->p_emul;
 1082 
 1083                 break;
 1084         case SYSTR_POLICY_MODIFY:
 1085                 DPRINTF(("%s: %d: code %d -> policy %d\n", __func__,
 1086                     pol->strp_num, pol->strp_code, pol->strp_policy));
 1087                 if (!POLICY_VALID(pol->strp_policy))
 1088                         return (EINVAL);
 1089                 TAILQ_FOREACH(strpol, &fst->policies, next)
 1090                     if (strpol->nr == pol->strp_num)
 1091                             break;
 1092                 if (strpol == NULL)
 1093                         return (EINVAL);
 1094                 if (pol->strp_code < 0 || pol->strp_code >= strpol->nsysent)
 1095                         return (EINVAL);
 1096                 strpol->sysent[pol->strp_code] = pol->strp_policy;
 1097                 break;
 1098         default:
 1099                 return (EINVAL);
 1100         }
 1101 
 1102         return (0);
 1103 }
 1104 
 1105 int
 1106 systrace_processready(struct str_process *strp)
 1107 {
 1108         if (ISSET(strp->flags, STR_PROC_ONQUEUE))
 1109                 return (EBUSY);
 1110 
 1111         if (!ISSET(strp->flags, STR_PROC_WAITANSWER))
 1112                 return (EBUSY);
 1113 
 1114         /* XXX - ignore until systrace knows about lwps. :-(
 1115         if (strp->proc->p_stat != LSSLEEP)
 1116                 return (EBUSY);
 1117         */
 1118         return (0);
 1119 }
 1120 
 1121 int
 1122 systrace_getcwd(struct fsystrace *fst, struct str_process *strp)
 1123 {
 1124 #ifdef __NetBSD__
 1125         struct cwdinfo *mycwdp, *cwdp;
 1126 #else
 1127         struct filedesc *myfdp, *fdp;
 1128 #endif
 1129         int error;
 1130 
 1131         DPRINTF(("%s: %d\n", __func__, strp->pid));
 1132 
 1133         error = systrace_processready(strp);
 1134         if (error)
 1135                 return (error);
 1136 
 1137 #ifdef __NetBSD__
 1138         mycwdp = curproc->p_cwdi;
 1139         cwdp = strp->proc->p_cwdi;
 1140         if (mycwdp == NULL || cwdp == NULL)
 1141                 return (EINVAL);
 1142 
 1143         /* Store our current values */
 1144         fst->fd_pid = strp->pid;
 1145         fst->fd_cdir = mycwdp->cwdi_cdir;
 1146         fst->fd_rdir = mycwdp->cwdi_rdir;
 1147 
 1148         if ((mycwdp->cwdi_cdir = cwdp->cwdi_cdir) != NULL)
 1149                 VREF(mycwdp->cwdi_cdir);
 1150         if ((mycwdp->cwdi_rdir = cwdp->cwdi_rdir) != NULL)
 1151                 VREF(mycwdp->cwdi_rdir);
 1152 #else
 1153         myfdp = curlwp->p_fd;
 1154         fdp = strp->proc->p_fd;
 1155         if (myfdp == NULL || fdp == NULL)
 1156                 return (EINVAL);
 1157 
 1158         /* Store our current values */
 1159         fst->fd_pid = strp->pid;
 1160         fst->fd_cdir = myfdp->fd_cdir;
 1161         fst->fd_rdir = myfdp->fd_rdir;
 1162 
 1163         if ((myfdp->fd_cdir = fdp->fd_cdir) != NULL)
 1164                 VREF(myfdp->fd_cdir);
 1165         if ((myfdp->fd_rdir = fdp->fd_rdir) != NULL)
 1166                 VREF(myfdp->fd_rdir);
 1167 #endif
 1168 
 1169         return (0);
 1170 }
 1171 
 1172 int
 1173 systrace_io(struct str_process *strp, struct systrace_io *io)
 1174 {
 1175         struct proc *t = strp->proc;
 1176         struct lwp *l = curlwp;
 1177         struct uio uio;
 1178         struct iovec iov;
 1179         int error = 0;
 1180 
 1181         DPRINTF(("%s: %u: %p(%lu)\n", __func__,
 1182             io->strio_pid, io->strio_offs, (u_long)io->strio_len));
 1183 
 1184         switch (io->strio_op) {
 1185         case SYSTR_READ:
 1186                 uio.uio_rw = UIO_READ;
 1187                 break;
 1188         case SYSTR_WRITE:
 1189                 uio.uio_rw = UIO_WRITE;
 1190                 break;
 1191         default:
 1192                 return (EINVAL);
 1193         }
 1194 
 1195         error = systrace_processready(strp);
 1196         if (error)
 1197                 goto out;
 1198 
 1199         iov.iov_base = io->strio_addr;
 1200         iov.iov_len = io->strio_len;
 1201         uio.uio_iov = &iov;
 1202         uio.uio_iovcnt = 1;
 1203         uio.uio_offset = (off_t)(unsigned long)io->strio_offs;
 1204         uio.uio_resid = io->strio_len;
 1205         uio.uio_vmspace = l->l_proc->p_vmspace;
 1206 
 1207         error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSYSTRACE,
 1208             t, NULL, NULL, NULL);
 1209         if (error)
 1210                 return (error);
 1211 
 1212 #ifdef __NetBSD__
 1213         error = process_domem(l, proc_representative_lwp(t), &uio);
 1214 #else
 1215         error = procfs_domem(p, t, NULL, &uio);
 1216 #endif
 1217         io->strio_len -= uio.uio_resid;
 1218  out:
 1219 
 1220         return (error);
 1221 }
 1222 
 1223 int
 1224 systrace_attach(struct fsystrace *fst, pid_t pid)
 1225 {
 1226         int error = 0;
 1227         struct proc *proc, *p = curproc;
 1228 
 1229         if ((proc = pfind(pid)) == NULL) {
 1230                 error = ESRCH;
 1231                 goto out;
 1232         }
 1233 
 1234         if (ISSET(proc->p_flag, P_INEXEC)) {
 1235                 error = EAGAIN;
 1236                 goto out;
 1237         }
 1238 
 1239         /*
 1240          * You can't attach to a process if:
 1241          *      (1) it's the process that's doing the attaching,
 1242          */
 1243         if (proc->p_pid == p->p_pid) {
 1244                 error = EINVAL;
 1245                 goto out;
 1246         }
 1247 
 1248         /*
 1249          *      (2) it's a system process
 1250          */
 1251         if (ISSET(proc->p_flag, P_SYSTEM)) {
 1252                 error = EPERM;
 1253                 goto out;
 1254         }
 1255 
 1256         /*
 1257          *      (3) it's being traced already
 1258          */
 1259         if (ISSET(proc->p_flag, P_SYSTRACE)) {
 1260                 error = EBUSY;
 1261                 goto out;
 1262         }
 1263 
 1264         /*
 1265          *      (4) the security model prevents it it.
 1266          */
 1267         error = kauth_authorize_process(kauth_cred_get(),
 1268             KAUTH_PROCESS_CANSYSTRACE, proc, NULL, NULL, NULL);
 1269         if (error)
 1270                 goto out;
 1271 
 1272         error = systrace_insert_process(fst, proc, NULL);
 1273 
 1274 #if defined(__NetBSD__) && defined(__HAVE_SYSCALL_INTERN)
 1275         /*
 1276          * Make sure we're using the version of the syscall handler that
 1277          * has systrace hooks.
 1278          */
 1279         if (!error)
 1280                 (*proc->p_emul->e_syscall_intern)(proc);
 1281 #endif
 1282  out:
 1283         return (error);
 1284 }
 1285 
 1286 void
 1287 systrace_execve0(struct proc *p)
 1288 {
 1289         struct str_process *strp;
 1290 
 1291         systrace_lock();
 1292         strp = p->p_systrace;
 1293         strp->isscript = 0;
 1294         systrace_unlock();
 1295 }
 1296 
 1297 void
 1298 systrace_execve1(char *path, struct proc *p)
 1299 {
 1300         struct str_process *strp;
 1301         struct fsystrace *fst;
 1302         struct str_message msg;
 1303         struct str_msg_execve *msg_execve;
 1304 
 1305         do {
 1306                 systrace_lock();
 1307                 strp = p->p_systrace;
 1308                 if (strp == NULL) {
 1309                         systrace_unlock();
 1310                         return;
 1311                 }
 1312 
 1313                 msg_execve = &msg.msg_data.msg_execve;
 1314                 fst = strp->parent;
 1315                 SYSTRACE_LOCK(fst, curlwp);
 1316                 systrace_unlock();
 1317 
 1318                 /*
 1319                  * susers will get the execve call anyway. Also, if
 1320                  * we're not allowed to control the process, escape.
 1321                  */
 1322                 if (fst->issuser ||
 1323                     fst->p_ruid != kauth_cred_getuid(p->p_cred) ||
 1324                     fst->p_rgid != kauth_cred_getgid(p->p_cred)) {
 1325                         SYSTRACE_UNLOCK(fst, curlwp);
 1326                         return;
 1327                 }
 1328 
 1329                 strlcpy(msg_execve->path, path, sizeof(msg_execve->path));
 1330         } while (systrace_make_msg(strp, SYSTR_MSG_EXECVE, &msg) != 0);
 1331 }
 1332 
 1333 /* Prepare to replace arguments */
 1334 
 1335 int
 1336 systrace_preprepl(struct str_process *strp, struct systrace_replace *repl)
 1337 {
 1338         size_t len;
 1339         int i, ret = 0;
 1340 
 1341         ret = systrace_processready(strp);
 1342         if (ret)
 1343                 return (ret);
 1344 
 1345         systrace_replacefree(strp);
 1346 
 1347         if (repl->strr_nrepl < 0 || repl->strr_nrepl > SYSTR_MAXARGS)
 1348                 return (EINVAL);
 1349 
 1350         for (i = 0, len = 0; i < repl->strr_nrepl; i++) {
 1351                 if (repl->strr_argind[i] < 0 ||
 1352                     repl->strr_argind[i] >= SYSTR_MAXARGS)
 1353                         return (EINVAL);
 1354                 if (repl->strr_offlen[i] == 0)
 1355                         continue;
 1356                 len += repl->strr_offlen[i];
 1357                 if (repl->strr_offlen[i] > SYSTR_MAXREPLEN ||
 1358                     repl->strr_off[i] > SYSTR_MAXREPLEN ||
 1359                     len > SYSTR_MAXREPLEN)
 1360                         return (EINVAL);
 1361                 if (repl->strr_offlen[i] + repl->strr_off[i] > len)
 1362                         return (EINVAL);
 1363         }
 1364 
 1365         /* Make sure that the length adds up */
 1366         if (repl->strr_len != len)
 1367                 return (EINVAL);
 1368 
 1369         /* Check against a maximum length */
 1370         if (repl->strr_len > SYSTR_MAXREPLEN)
 1371                 return (EINVAL);
 1372 
 1373         strp->replace = (struct systrace_replace *)
 1374             malloc(sizeof(struct systrace_replace) + len, M_XDATA, M_WAITOK);
 1375 
 1376         memcpy(strp->replace, repl, sizeof(struct systrace_replace));
 1377         ret = copyin(repl->strr_base, strp->replace + 1, len);
 1378         if (ret) {
 1379                 free(strp->replace, M_XDATA);
 1380                 strp->replace = NULL;
 1381                 return (ret);
 1382         }
 1383 
 1384         /* Adjust the offset */
 1385         repl = strp->replace;
 1386         repl->strr_base = (caddr_t)(repl + 1);
 1387 
 1388         return (0);
 1389 }
 1390 
 1391 /*
 1392  * Replace the arguments with arguments from the monitoring process.
 1393  */
 1394 
 1395 int
 1396 systrace_replace(struct str_process *strp, size_t argsize, register_t args[])
 1397 {
 1398         struct proc *p = strp->proc;
 1399         struct systrace_replace *repl = strp->replace;
 1400         caddr_t sg, kdata, udata, kbase, ubase;
 1401         int i, maxarg, ind, ret = 0;
 1402 
 1403         maxarg = argsize/sizeof(register_t);
 1404 #ifdef __NetBSD__
 1405         sg = stackgap_init(p, 0);
 1406         ubase = stackgap_alloc(p, &sg, repl->strr_len);
 1407 #else
 1408         sg = stackgap_init(p->p_emul);
 1409         ubase = stackgap_alloc(&sg, repl->strr_len);
 1410 #endif
 1411         if (ubase == NULL) {
 1412                 ret = EINVAL;
 1413                 goto out;
 1414         }
 1415 
 1416         kbase = repl->strr_base;
 1417         for (i = 0; i < maxarg && i < repl->strr_nrepl; i++) {
 1418                 ind = repl->strr_argind[i];
 1419                 if (ind < 0 || ind >= maxarg) {
 1420                         ret = EINVAL;
 1421                         goto out;
 1422                 }
 1423                 if (repl->strr_offlen[i] == 0) {
 1424                         args[ind] = repl->strr_off[i];
 1425                         continue;
 1426                 }
 1427                 kdata = kbase + repl->strr_off[i];
 1428                 udata = ubase + repl->strr_off[i];
 1429                 if (repl->strr_flags[i] & SYSTR_NOLINKS) {
 1430                         ret = systrace_fname(strp, kdata, repl->strr_offlen[i]);
 1431                         if (ret != 0)
 1432                                 goto out;
 1433                 }
 1434                 if (copyout(kdata, udata, repl->strr_offlen[i])) {
 1435                         ret = EINVAL;
 1436                         goto out;
 1437                 }
 1438 
 1439                 /* Replace the argument with the new address */
 1440                 args[ind] = (register_t)(intptr_t)udata;
 1441         }
 1442 
 1443  out:
 1444         return (ret);
 1445 }
 1446 
 1447 int
 1448 systrace_fname(struct str_process *strp, caddr_t kdata, size_t len)
 1449 {
 1450         if (strp->nfname >= SYSTR_MAXFNAME || len < 2)
 1451                 return EINVAL;
 1452 
 1453         strp->fname[strp->nfname] = kdata;
 1454         strp->fname[strp->nfname][len - 1] = '\0';
 1455         strp->nfname++;
 1456 
 1457         return 0;
 1458 }
 1459 
 1460 void
 1461 systrace_replacefree(struct str_process *strp)
 1462 {
 1463 
 1464         if (strp->replace != NULL) {
 1465                 free(strp->replace, M_XDATA);
 1466                 strp->replace = NULL;
 1467         }
 1468         while (strp->nfname > 0) {
 1469                 strp->nfname--;
 1470                 strp->fname[strp->nfname] = NULL;
 1471         }
 1472 }
 1473 
 1474 int
 1475 systrace_scriptname(struct proc *p, char *dst)
 1476 {
 1477         struct str_process *strp;
 1478         struct fsystrace *fst;
 1479         int error = 0;
 1480 
 1481         systrace_lock();
 1482         strp = p->p_systrace;
 1483         if (strp == NULL) {
 1484                 systrace_unlock();
 1485                 return (EINVAL);
 1486         }
 1487 
 1488         fst = strp->parent;
 1489 
 1490         SYSTRACE_LOCK(fst, curlwp);
 1491         systrace_unlock();
 1492 
 1493         if (!fst->issuser && (ISSET(p->p_flag, P_SUGID) ||
 1494                               fst->p_ruid != kauth_cred_getuid(p->p_cred) ||
 1495                               fst->p_rgid != kauth_cred_getgid(p->p_cred))) {
 1496                 error = EPERM;
 1497                 goto out;
 1498         }
 1499 
 1500         if (strp->scriptname[0] == '\0') {
 1501                 error = ENOENT;
 1502                 goto out;
 1503         }
 1504 
 1505         strlcpy(dst, strp->scriptname, MAXPATHLEN);
 1506         strp->isscript = 1;
 1507 
 1508  out:
 1509         strp->scriptname[0] = '\0';
 1510         SYSTRACE_UNLOCK(fst, curlwp);
 1511 
 1512         return (error);
 1513 }
 1514 
 1515 void
 1516 systrace_namei(struct nameidata *ndp)
 1517 {
 1518         struct str_process *strp;
 1519         struct fsystrace *fst = NULL; /* XXXGCC */
 1520         struct componentname *cnp = &ndp->ni_cnd;
 1521         size_t i;
 1522         int hamper = 0;
 1523 
 1524         systrace_lock();
 1525         strp = cnp->cn_lwp->l_proc->p_systrace;
 1526         if (strp != NULL) {
 1527                 fst = strp->parent;
 1528                 SYSTRACE_LOCK(fst, curlwp);
 1529                 systrace_unlock();
 1530 
 1531                 for (i = 0; i < strp->nfname; i++) {
 1532                         if (strcmp(cnp->cn_pnbuf, strp->fname[i]) == 0) {
 1533                                 hamper = 1;
 1534                                 break;
 1535                         }
 1536                 }
 1537 
 1538                 if (!hamper && strp->isscript &&
 1539                     strcmp(cnp->cn_pnbuf, strp->scriptname) == 0)
 1540                         hamper = 1;
 1541 
 1542                 SYSTRACE_UNLOCK(fst, curlwp);
 1543         } else
 1544                 systrace_unlock();
 1545 
 1546         if (hamper) {
 1547                 /* ELOOP if namei() tries to readlink */
 1548                 ndp->ni_loopcnt = MAXSYMLINKS;
 1549                 cnp->cn_flags &= ~FOLLOW;
 1550                 cnp->cn_flags |= NOFOLLOW;
 1551         }
 1552 }
 1553 
 1554 struct str_process *
 1555 systrace_findpid(struct fsystrace *fst, pid_t pid)
 1556 {
 1557         struct str_process *strp;
 1558         struct proc *proc = NULL;
 1559 
 1560         TAILQ_FOREACH(strp, &fst->processes, next)
 1561             if (strp->pid == pid)
 1562                     break;
 1563 
 1564         if (strp == NULL)
 1565                 return (NULL);
 1566 
 1567         proc = systrace_find(strp);
 1568 
 1569         return (proc ? strp : NULL);
 1570 }
 1571 
 1572 int
 1573 systrace_detach(struct str_process *strp)
 1574 {
 1575         struct proc *proc;
 1576         struct fsystrace *fst = NULL;
 1577         int error = 0;
 1578 
 1579         DPRINTF(("%s: Trying to detach from %d\n", __func__, strp->pid));
 1580 
 1581         if ((proc = systrace_find(strp)) != NULL) {
 1582                 CLR(proc->p_flag, P_SYSTRACE);
 1583                 proc->p_systrace = NULL;
 1584         } else
 1585                 error = ESRCH;
 1586 
 1587         if (ISSET(strp->flags, STR_PROC_WAITANSWER)) {
 1588                 CLR(strp->flags, STR_PROC_WAITANSWER);
 1589                 wakeup(strp);
 1590         }
 1591 
 1592         fst = strp->parent;
 1593         systrace_wakeup(fst);
 1594 
 1595         TAILQ_REMOVE(&fst->processes, strp, next);
 1596         fst->nprocesses--;
 1597 
 1598         if (strp->policy)
 1599                 systrace_closepolicy(fst, strp->policy);
 1600         systrace_replacefree(strp);
 1601         pool_put(&systr_proc_pl, strp);
 1602 
 1603         return (error);
 1604 }
 1605 
 1606 void
 1607 systrace_closepolicy(struct fsystrace *fst, struct str_policy *policy)
 1608 {
 1609         if (--policy->refcount)
 1610                 return;
 1611 
 1612         fst->npolicies--;
 1613 
 1614         if (policy->nsysent)
 1615                 free(policy->sysent, M_XDATA);
 1616 
 1617         TAILQ_REMOVE(&fst->policies, policy, next);
 1618 
 1619         pool_put(&systr_policy_pl, policy);
 1620 }
 1621 
 1622 
 1623 int
 1624 systrace_insert_process(struct fsystrace *fst, struct proc *proc,
 1625     struct str_process **pstrp)
 1626 {
 1627         struct str_process *strp;
 1628 
 1629         strp = pool_get(&systr_proc_pl, PR_NOWAIT);
 1630         if (strp == NULL)
 1631                 return (ENOBUFS);
 1632 
 1633         memset((caddr_t)strp, 0, sizeof(struct str_process));
 1634         strp->pid = proc->p_pid;
 1635         strp->proc = proc;
 1636         strp->parent = fst;
 1637 
 1638         TAILQ_INSERT_TAIL(&fst->processes, strp, next);
 1639         fst->nprocesses++;
 1640 
 1641         proc->p_systrace = strp;
 1642         SET(proc->p_flag, P_SYSTRACE);
 1643 
 1644         /* Pass the new pointer back to the caller */
 1645         if (pstrp != NULL)
 1646                 *pstrp = strp;
 1647 
 1648         return (0);
 1649 }
 1650 
 1651 struct str_policy *
 1652 systrace_newpolicy(struct fsystrace *fst, int maxents)
 1653 {
 1654         struct str_policy *pol;
 1655         int i;
 1656 
 1657         if (fst->npolicies > SYSTR_MAX_POLICIES && !fst->issuser) {
 1658                 struct str_policy *tmp;
 1659 
 1660                 /* Try to find a policy for freeing */
 1661                 TAILQ_FOREACH(tmp, &fst->policies, next) {
 1662                         if (tmp->refcount == 1)
 1663                                 break;
 1664                 }
 1665 
 1666                 if (tmp == NULL)
 1667                         return (NULL);
 1668 
 1669                 /* Notify userland about freed policy */
 1670                 systrace_msg_policyfree(fst, tmp);
 1671                 /* Free this policy */
 1672                 systrace_closepolicy(fst, tmp);
 1673         }
 1674 
 1675         pol = pool_get(&systr_policy_pl, PR_NOWAIT);
 1676         if (pol == NULL)
 1677                 return (NULL);
 1678 
 1679         DPRINTF(("%s: allocating %d -> %lu\n", __func__,
 1680                      maxents, (u_long)maxents * sizeof(int)));
 1681 
 1682         memset((caddr_t)pol, 0, sizeof(struct str_policy));
 1683 
 1684         pol->sysent = (u_char *)malloc(maxents * sizeof(u_char),
 1685             M_XDATA, M_WAITOK);
 1686         pol->nsysent = maxents;
 1687         for (i = 0; i < maxents; i++)
 1688                 pol->sysent[i] = SYSTR_POLICY_ASK;
 1689 
 1690         fst->npolicies++;
 1691         pol->nr = fst->npolicynr++;
 1692         pol->refcount = 1;
 1693 
 1694         TAILQ_INSERT_TAIL(&fst->policies, pol, next);
 1695 
 1696         return (pol);
 1697 }
 1698 
 1699 int
 1700 systrace_msg_ask(struct fsystrace *fst, struct str_process *strp, int code,
 1701     size_t argsize, register_t args[])
 1702 {
 1703         struct str_message msg;
 1704         struct str_msg_ask *msg_ask = &msg.msg_data.msg_ask;
 1705         int i;
 1706 
 1707         msg_ask->code = code;
 1708         msg_ask->argsize = argsize;
 1709         for (i = 0; i < (argsize/sizeof(register_t)) && i < SYSTR_MAXARGS; i++)
 1710                 msg_ask->args[i] = args[i];
 1711 
 1712         return (systrace_make_msg(strp, SYSTR_MSG_ASK, &msg));
 1713 }
 1714 
 1715 int
 1716 systrace_msg_result(struct fsystrace *fst, struct str_process *strp, int error,
 1717     int code, size_t argsize, register_t args[], register_t rval[])
 1718 {
 1719         struct str_message msg;
 1720         struct str_msg_ask *msg_ask = &msg.msg_data.msg_ask;
 1721         int i;
 1722 
 1723         msg_ask->code = code;
 1724         msg_ask->argsize = argsize;
 1725         msg_ask->result = error;
 1726         for (i = 0; i < (argsize/sizeof(register_t)) && i < SYSTR_MAXARGS; i++)
 1727                 msg_ask->args[i] = args[i];
 1728 
 1729         msg_ask->rval[0] = rval[0];
 1730         msg_ask->rval[1] = rval[1];
 1731 
 1732         return (systrace_make_msg(strp, SYSTR_MSG_RES, &msg));
 1733 }
 1734 
 1735 int
 1736 systrace_msg_emul(struct fsystrace *fst, struct str_process *strp)
 1737 {
 1738         struct str_message msg;
 1739         struct str_msg_emul *msg_emul = &msg.msg_data.msg_emul;
 1740         struct proc *p = strp->proc;
 1741 
 1742         memcpy(msg_emul->emul, p->p_emul->e_name, SYSTR_EMULEN);
 1743 
 1744         return (systrace_make_msg(strp, SYSTR_MSG_EMUL, &msg));
 1745 }
 1746 
 1747 int
 1748 systrace_msg_ugid(struct fsystrace *fst, struct str_process *strp)
 1749 {
 1750         struct str_message msg;
 1751         struct str_msg_ugid *msg_ugid = &msg.msg_data.msg_ugid;
 1752         struct proc *p = strp->proc;
 1753 
 1754         msg_ugid->uid = kauth_cred_getuid(p->p_cred);
 1755         msg_ugid->gid = kauth_cred_getgid(p->p_cred);
 1756 
 1757         return (systrace_make_msg(strp, SYSTR_MSG_UGID, &msg));
 1758 }
 1759 
 1760 int
 1761 systrace_make_msg(struct str_process *strp, int type, struct str_message *tmsg)
 1762 {
 1763         struct str_msgcontainer *cont;
 1764         struct str_message *msg;
 1765         struct fsystrace *fst = strp->parent;
 1766         int st;
 1767 
 1768         cont = pool_get(&systr_msgcontainer_pl, PR_WAITOK);
 1769         memset(cont, 0, sizeof(struct str_msgcontainer));
 1770         cont->strp = strp;
 1771 
 1772         msg = &cont->msg;
 1773 
 1774         /* Copy the already filled in fields */
 1775         memcpy(&msg->msg_data, &tmsg->msg_data, sizeof(msg->msg_data));
 1776 
 1777         /* Add the extra fields to the message */
 1778         msg->msg_seqnr = ++strp->seqnr;
 1779         msg->msg_type = type;
 1780         msg->msg_pid = strp->pid;
 1781         if (strp->policy)
 1782                 msg->msg_policy = strp->policy->nr;
 1783         else
 1784                 msg->msg_policy = -1;
 1785 
 1786         SET(strp->flags, STR_PROC_WAITANSWER);
 1787         if (ISSET(strp->flags, STR_PROC_ONQUEUE))
 1788                 goto out;
 1789 
 1790         TAILQ_INSERT_TAIL(&fst->messages, cont, next);
 1791         SET(strp->flags, STR_PROC_ONQUEUE);
 1792 
 1793  out:
 1794         systrace_wakeup(fst);
 1795 
 1796         /* Release the lock - XXX */
 1797         SYSTRACE_UNLOCK(fst, strp->proc);
 1798 
 1799         while (1) {
 1800                 int f;
 1801                 f = curlwp->l_flag & L_SA;
 1802                 curlwp->l_flag &= ~L_SA;
 1803                 st = tsleep(strp, PWAIT, "systrmsg", 0);
 1804                 curlwp->l_flag |= f;
 1805                 if (st != 0)
 1806                         return (ERESTART);
 1807                 /* If we detach, then everything is permitted */
 1808                 if ((strp = curproc->p_systrace) == NULL)
 1809                         return (0);
 1810                 if (!ISSET(strp->flags, STR_PROC_WAITANSWER))
 1811                         break;
 1812         }
 1813 
 1814         return (0);
 1815 }
 1816 
 1817 int
 1818 systrace_msg_child(struct fsystrace *fst, struct str_process *strp, pid_t npid)
 1819 {
 1820         struct str_msgcontainer *cont;
 1821         struct str_message *msg;
 1822         struct str_msg_child *msg_child;
 1823 
 1824         cont = pool_get(&systr_msgcontainer_pl, PR_WAITOK);
 1825         memset(cont, 0, sizeof(struct str_msgcontainer));
 1826         cont->strp = strp;
 1827 
 1828         msg = &cont->msg;
 1829 
 1830         DPRINTF(("%s: %p: pid %d -> pid %d\n", __func__,
 1831                     msg, strp->pid, npid));
 1832 
 1833         msg_child = &msg->msg_data.msg_child;
 1834 
 1835         msg->msg_type = SYSTR_MSG_CHILD;
 1836         msg->msg_pid = strp->pid;
 1837         if (strp->policy)
 1838                 msg->msg_policy = strp->policy->nr;
 1839         else
 1840                 msg->msg_policy = -1;
 1841         msg_child->new_pid = npid;
 1842 
 1843         TAILQ_INSERT_TAIL(&fst->messages, cont, next);
 1844 
 1845         systrace_wakeup(fst);
 1846 
 1847         return (0);
 1848 }
 1849 
 1850 int
 1851 systrace_msg_policyfree(struct fsystrace *fst, struct str_policy *strpol)
 1852 {
 1853         struct str_msgcontainer *cont;
 1854         struct str_message *msg;
 1855 
 1856         cont = pool_get(&systr_msgcontainer_pl, PR_WAITOK);
 1857         memset(cont, 0, sizeof(struct str_msgcontainer));
 1858 
 1859         msg = &cont->msg;
 1860 
 1861         DPRINTF(("%s: free %d\n", __func__, strpol->nr));
 1862 
 1863         msg->msg_type = SYSTR_MSG_POLICYFREE;
 1864         msg->msg_policy = strpol->nr;
 1865 
 1866         TAILQ_INSERT_TAIL(&fst->messages, cont, next);
 1867 
 1868         systrace_wakeup(fst);
 1869 
 1870         return (0);
 1871 }

Cache object: 7b99fa5c1d4b93808896e5ddd4991127


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