Annotation of src/usr.bin/file/sandbox.c, Revision 1.1
1.1 ! nicm 1: /* $OpenBSD: file.c,v 1.33 2015/04/26 19:53:50 nicm Exp $ */
! 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:
! 120: do
! 121: pid = waitpid(pid, &status, WUNTRACED);
! 122: while (pid == -1 && errno == EINTR);
! 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: }