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