Annotation of src/usr.bin/file/sandbox.c, Revision 1.5
1.5 ! deraadt 1: /* $OpenBSD: sandbox.c,v 1.4 2015/04/30 14:30:53 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 },
52: { SYS_madvise, SYSTR_POLICY_PERMIT },
53: { SYS_mmap, SYSTR_POLICY_PERMIT },
54: { SYS_mprotect, SYSTR_POLICY_PERMIT },
55: { SYS_mquery, SYSTR_POLICY_PERMIT },
56: { SYS_munmap, SYSTR_POLICY_PERMIT },
57: { SYS_read, SYSTR_POLICY_PERMIT },
58: { SYS_recvmsg, SYSTR_POLICY_PERMIT },
59: { SYS_sendmsg, SYSTR_POLICY_PERMIT },
60: { SYS_sigprocmask, SYSTR_POLICY_PERMIT },
61: { SYS_write, SYSTR_POLICY_PERMIT },
62:
63: { -1, -1 }
64: };
65:
66: static int
67: sandbox_find(int syscallnum)
68: {
69: int i;
70:
71: for (i = 0; allowed_syscalls[i].syscallnum != -1; i++) {
72: if (allowed_syscalls[i].syscallnum == syscallnum)
73: return (allowed_syscalls[i].action);
74: }
75: return (SYSTR_POLICY_KILL);
76: }
77:
78: static int
79: sandbox_child(const char *user)
80: {
81: struct passwd *pw;
82:
83: if (geteuid() == 0) {
84: pw = getpwnam(user);
85: if (pw == NULL)
86: errx(1, "unknown user %s", user);
87: if (setgroups(1, &pw->pw_gid) != 0)
88: err(1, "setgroups");
89: if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0)
90: err(1, "setresgid");
91: if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0)
92: err(1, "setresuid");
93: }
94:
95: if (kill(getpid(), SIGSTOP) != 0)
96: err(1, "kill(SIGSTOP)");
97: return (0);
98: }
99:
100: int
101: sandbox_fork(const char *user)
102: {
103: pid_t pid;
104: int status, devfd, fd, i;
105: struct systrace_policy policy;
106:
107: switch (pid = fork()) {
108: case -1:
109: err(1, "fork");
110: case 0:
111: return (sandbox_child(user));
112: }
113:
1.4 nicm 114: /*
115: * Wait for the child to stop itself with SIGSTOP before assigning the
116: * policy, before that it might still be calling syscalls the policy
117: * would block.
118: */
1.2 deraadt 119: do {
1.1 nicm 120: pid = waitpid(pid, &status, WUNTRACED);
1.2 deraadt 121: } while (pid == -1 && errno == EINTR);
1.1 nicm 122: if (!WIFSTOPPED(status))
123: errx(1, "child not stopped");
124:
125: devfd = open("/dev/systrace", O_RDONLY);
126: if (devfd == -1)
127: err(1, "open(\"/dev/systrace\")");
128: if (ioctl(devfd, STRIOCCLONE, &fd) == -1)
129: err(1, "ioctl(STRIOCCLONE)");
130: close(devfd);
131:
132: if (ioctl(fd, STRIOCATTACH, &pid) == -1)
133: err(1, "ioctl(STRIOCATTACH)");
134:
135: memset(&policy, 0, sizeof policy);
136: policy.strp_op = SYSTR_POLICY_NEW;
137: policy.strp_maxents = SYS_MAXSYSCALL;
138: if (ioctl(fd, STRIOCPOLICY, &policy) == -1)
139: err(1, "ioctl(STRIOCPOLICY/NEW)");
140: policy.strp_op = SYSTR_POLICY_ASSIGN;
141: policy.strp_pid = pid;
142: if (ioctl(fd, STRIOCPOLICY, &policy) == -1)
143: err(1, "ioctl(STRIOCPOLICY/ASSIGN)");
144:
145: for (i = 0; i < SYS_MAXSYSCALL; i++) {
146: policy.strp_op = SYSTR_POLICY_MODIFY;
147: policy.strp_code = i;
148: policy.strp_policy = sandbox_find(i);
149: if (ioctl(fd, STRIOCPOLICY, &policy) == -1)
150: err(1, "ioctl(STRIOCPOLICY/MODIFY)");
151: }
152:
153: if (kill(pid, SIGCONT) != 0)
154: err(1, "kill(SIGCONT)");
155: return (pid);
156: }