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: }