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

Cache object: 04b9f05eec10a7c1ba6dbf0ef5d29000


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