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

1.9     ! guenther    1: /* $OpenBSD: sandbox.c,v 1.8 2015/06/04 22:56:33 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 },
1.5       deraadt    45:        { SYS_fcntl, SYSTR_POLICY_PERMIT },
                     46:        { SYS_fstat, SYSTR_POLICY_PERMIT },
1.1       nicm       47:        { SYS_getdtablecount, SYSTR_POLICY_PERMIT },
                     48:        { SYS_getentropy, SYSTR_POLICY_PERMIT },
                     49:        { SYS_getpid, SYSTR_POLICY_PERMIT },
                     50:        { SYS_getrlimit, SYSTR_POLICY_PERMIT },
                     51:        { SYS_issetugid, SYSTR_POLICY_PERMIT },
1.9     ! guenther   52:        { SYS_kbind, SYSTR_POLICY_PERMIT },
1.1       nicm       53:        { SYS_madvise, SYSTR_POLICY_PERMIT },
                     54:        { SYS_mmap, SYSTR_POLICY_PERMIT },
                     55:        { SYS_mprotect, SYSTR_POLICY_PERMIT },
                     56:        { SYS_mquery, SYSTR_POLICY_PERMIT },
                     57:        { SYS_munmap, SYSTR_POLICY_PERMIT },
                     58:        { SYS_read, SYSTR_POLICY_PERMIT },
                     59:        { SYS_recvmsg, SYSTR_POLICY_PERMIT },
                     60:        { SYS_sendmsg, SYSTR_POLICY_PERMIT },
                     61:        { SYS_sigprocmask, SYSTR_POLICY_PERMIT },
                     62:        { SYS_write, SYSTR_POLICY_PERMIT },
                     63:
                     64:        { -1, -1 }
                     65: };
                     66:
                     67: static int
                     68: sandbox_find(int syscallnum)
                     69: {
                     70:        int     i;
                     71:
                     72:        for (i = 0; allowed_syscalls[i].syscallnum != -1; i++) {
                     73:                if (allowed_syscalls[i].syscallnum == syscallnum)
                     74:                        return (allowed_syscalls[i].action);
                     75:        }
                     76:        return (SYSTR_POLICY_KILL);
                     77: }
                     78:
                     79: static int
                     80: sandbox_child(const char *user)
                     81: {
                     82:        struct passwd   *pw;
                     83:
                     84:        if (geteuid() == 0) {
                     85:                pw = getpwnam(user);
                     86:                if (pw == NULL)
                     87:                        errx(1, "unknown user %s", user);
                     88:                if (setgroups(1, &pw->pw_gid) != 0)
                     89:                        err(1, "setgroups");
                     90:                if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0)
                     91:                        err(1, "setresgid");
                     92:                if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0)
                     93:                        err(1, "setresuid");
                     94:        }
                     95:
                     96:        if (kill(getpid(), SIGSTOP) != 0)
                     97:                err(1, "kill(SIGSTOP)");
                     98:        return (0);
                     99: }
                    100:
                    101: int
                    102: sandbox_fork(const char *user)
                    103: {
                    104:        pid_t                    pid;
                    105:        int                      status, devfd, fd, i;
                    106:        struct systrace_policy   policy;
                    107:
                    108:        switch (pid = fork()) {
                    109:        case -1:
                    110:                err(1, "fork");
                    111:        case 0:
                    112:                return (sandbox_child(user));
                    113:        }
                    114:
1.4       nicm      115:        /*
                    116:         * Wait for the child to stop itself with SIGSTOP before assigning the
                    117:         * policy, before that it might still be calling syscalls the policy
                    118:         * would block.
                    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)
1.8       nicm      134:                goto out;
1.1       nicm      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:
1.8       nicm      154: out:
1.1       nicm      155:        if (kill(pid, SIGCONT) != 0)
                    156:                err(1, "kill(SIGCONT)");
                    157:        return (pid);
                    158: }