[BACK]Return to systrace.c CVS log [TXT][DIR] Up to [local] / sys / dev

Annotation of sys/dev/systrace.c, Revision 1.1

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

CVSweb