[BACK]Return to sandbox.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / file

Annotation of src/usr.bin/file/sandbox.c, Revision 1.2

1.2     ! deraadt     1: /* $OpenBSD: sandbox.c,v 1.1 2015/04/27 13:52:17 nicm Exp $ */
1.1       nicm        2:
                      3: /*
                      4:  * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
                     15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
                     16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/types.h>
                     20: #include <sys/ioctl.h>
                     21: #include <sys/syscall.h>
                     22: #include <sys/wait.h>
                     23:
                     24: #include <dev/systrace.h>
                     25:
                     26: #include <errno.h>
                     27: #include <fcntl.h>
                     28: #include <pwd.h>
                     29: #include <signal.h>
                     30: #include <unistd.h>
                     31:
                     32: #include "file.h"
                     33: #include "magic.h"
                     34: #include "xmalloc.h"
                     35:
                     36: static const struct
                     37: {
                     38:        int syscallnum;
                     39:        int action;
                     40: } allowed_syscalls[] = {
                     41:        { SYS_open, SYSTR_POLICY_NEVER }, /* for strerror */
                     42:
                     43:        { SYS_close, SYSTR_POLICY_PERMIT },
                     44:        { SYS_exit, SYSTR_POLICY_PERMIT },
                     45:        { SYS_getdtablecount, SYSTR_POLICY_PERMIT },
                     46:        { SYS_getentropy, SYSTR_POLICY_PERMIT },
                     47:        { SYS_getpid, SYSTR_POLICY_PERMIT },
                     48:        { SYS_getrlimit, SYSTR_POLICY_PERMIT },
                     49:        { SYS_issetugid, SYSTR_POLICY_PERMIT },
                     50:        { SYS_madvise, SYSTR_POLICY_PERMIT },
                     51:        { SYS_mmap, SYSTR_POLICY_PERMIT },
                     52:        { SYS_mprotect, SYSTR_POLICY_PERMIT },
                     53:        { SYS_mquery, SYSTR_POLICY_PERMIT },
                     54:        { SYS_munmap, SYSTR_POLICY_PERMIT },
                     55:        { SYS_read, SYSTR_POLICY_PERMIT },
                     56:        { SYS_recvmsg, SYSTR_POLICY_PERMIT },
                     57:        { SYS_sendmsg, SYSTR_POLICY_PERMIT },
                     58:        { SYS_sigprocmask, SYSTR_POLICY_PERMIT },
                     59:        { SYS_write, SYSTR_POLICY_PERMIT },
                     60:
                     61:        { -1, -1 }
                     62: };
                     63:
                     64: static int
                     65: sandbox_find(int syscallnum)
                     66: {
                     67:        int     i;
                     68:
                     69:        for (i = 0; allowed_syscalls[i].syscallnum != -1; i++) {
                     70:                if (allowed_syscalls[i].syscallnum == syscallnum)
                     71:                        return (allowed_syscalls[i].action);
                     72:        }
                     73:        return (SYSTR_POLICY_KILL);
                     74: }
                     75:
                     76: static int
                     77: sandbox_child(const char *user)
                     78: {
                     79:        struct passwd   *pw;
                     80:
                     81:        /*
                     82:         * If we don't set streams to line buffered explicitly, stdio uses
                     83:         * isatty() which means ioctl() - too nasty to let through the systrace
                     84:         * policy.
                     85:         */
                     86:        setvbuf(stdout, NULL, _IOLBF, 0);
                     87:        setvbuf(stderr, NULL, _IOLBF, 0);
                     88:
                     89:        if (geteuid() == 0) {
                     90:                pw = getpwnam(user);
                     91:                if (pw == NULL)
                     92:                        errx(1, "unknown user %s", user);
                     93:                if (setgroups(1, &pw->pw_gid) != 0)
                     94:                        err(1, "setgroups");
                     95:                if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0)
                     96:                        err(1, "setresgid");
                     97:                if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0)
                     98:                        err(1, "setresuid");
                     99:        }
                    100:
                    101:        if (kill(getpid(), SIGSTOP) != 0)
                    102:                err(1, "kill(SIGSTOP)");
                    103:        return (0);
                    104: }
                    105:
                    106: int
                    107: sandbox_fork(const char *user)
                    108: {
                    109:        pid_t                    pid;
                    110:        int                      status, devfd, fd, i;
                    111:        struct systrace_policy   policy;
                    112:
                    113:        switch (pid = fork()) {
                    114:        case -1:
                    115:                err(1, "fork");
                    116:        case 0:
                    117:                return (sandbox_child(user));
                    118:        }
                    119:
1.2     ! deraadt   120:        do {
1.1       nicm      121:                pid = waitpid(pid, &status, WUNTRACED);
1.2     ! deraadt   122:        } while (pid == -1 && errno == EINTR);
1.1       nicm      123:        if (!WIFSTOPPED(status))
                    124:                errx(1, "child not stopped");
                    125:
                    126:        devfd = open("/dev/systrace", O_RDONLY);
                    127:        if (devfd == -1)
                    128:                err(1, "open(\"/dev/systrace\")");
                    129:        if (ioctl(devfd, STRIOCCLONE, &fd) == -1)
                    130:                err(1, "ioctl(STRIOCCLONE)");
                    131:        close(devfd);
                    132:
                    133:        if (ioctl(fd, STRIOCATTACH, &pid) == -1)
                    134:                err(1, "ioctl(STRIOCATTACH)");
                    135:
                    136:        memset(&policy, 0, sizeof policy);
                    137:        policy.strp_op = SYSTR_POLICY_NEW;
                    138:        policy.strp_maxents = SYS_MAXSYSCALL;
                    139:        if (ioctl(fd, STRIOCPOLICY, &policy) == -1)
                    140:                err(1, "ioctl(STRIOCPOLICY/NEW)");
                    141:        policy.strp_op = SYSTR_POLICY_ASSIGN;
                    142:        policy.strp_pid = pid;
                    143:        if (ioctl(fd, STRIOCPOLICY, &policy) == -1)
                    144:                err(1, "ioctl(STRIOCPOLICY/ASSIGN)");
                    145:
                    146:        for (i = 0; i < SYS_MAXSYSCALL; i++) {
                    147:                policy.strp_op = SYSTR_POLICY_MODIFY;
                    148:                policy.strp_code = i;
                    149:                policy.strp_policy = sandbox_find(i);
                    150:                if (ioctl(fd, STRIOCPOLICY, &policy) == -1)
                    151:                        err(1, "ioctl(STRIOCPOLICY/MODIFY)");
                    152:        }
                    153:
                    154:        if (kill(pid, SIGCONT) != 0)
                    155:                err(1, "kill(SIGCONT)");
                    156:        return (pid);
                    157: }