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

Cache object: acd88e03c4ad9bed2eff9b6aab3124f0


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