1 /* $OpenBSD: kern_pledge.c,v 1.165 2016/04/28 14:25:08 beck Exp $ */
4 * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
5 * Copyright (c) 2015 Theo de Raadt <deraadt@openbsd.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 #include <sys/syscall.h>
32 #define SYS_MAXSYSCALL 1000
35 * Ordered in blocks starting with least risky and most required.
37 const uint64_t pledge_syscalls[SYS_MAXSYSCALL] = {
41 [SYS_exit] = PLEDGE_ALWAYS,
42 // [SYS_kbind] = PLEDGE_ALWAYS,
43 // [SYS___get_tcb] = PLEDGE_ALWAYS,
44 // [SYS_pledge] = PLEDGE_ALWAYS,
45 // [SYS_sendsyslog] = PLEDGE_ALWAYS, /* stack protector reporting */
46 // [SYS_osendsyslog] = PLEDGE_ALWAYS, /* obsolete sendsyslog */
47 // [SYS_thrkill] = PLEDGE_ALWAYS, /* raise, abort, stack pro */
48 // [SYS_utrace] = PLEDGE_ALWAYS, /* ltrace(1) from ld.so */
50 /* "getting" information about self is considered safe */
51 [SYS_getuid] = PLEDGE_STDIO,
52 [SYS_geteuid] = PLEDGE_STDIO,
53 [SYS_getresuid] = PLEDGE_STDIO,
54 [SYS_getgid] = PLEDGE_STDIO,
55 [SYS_getegid] = PLEDGE_STDIO,
56 [SYS_getresgid] = PLEDGE_STDIO,
57 [SYS_getgroups] = PLEDGE_STDIO,
58 // [SYS_getlogin59] = PLEDGE_STDIO,
59 // [SYS_getlogin_r] = PLEDGE_STDIO,
60 [SYS_getpgrp] = PLEDGE_STDIO,
61 [SYS_getpgid] = PLEDGE_STDIO,
62 [SYS_getppid] = PLEDGE_STDIO,
63 [SYS_getsid] = PLEDGE_STDIO,
64 // [SYS_getthrid] = PLEDGE_STDIO,
65 [SYS_getrlimit] = PLEDGE_STDIO,
66 [SYS_gettimeofday] = PLEDGE_STDIO,
67 // [SYS_getdtablecount] = PLEDGE_STDIO,
68 [SYS_getrusage] = PLEDGE_STDIO,
69 // [SYS_issetugid] = PLEDGE_STDIO,
70 [SYS_clock_getres] = PLEDGE_STDIO,
71 [SYS_clock_gettime] = PLEDGE_STDIO,
72 [SYS_getpid] = PLEDGE_STDIO,
75 * Almost exclusively read-only, Very narrow subset.
76 * Use of "route", "inet", "dns", "ps", or "vminfo"
79 // [SYS_sysctl] = PLEDGE_STDIO,
81 /* Support for malloc(3) family of operations */
82 // [SYS_getentropy] = PLEDGE_STDIO,
83 [SYS_madvise] = PLEDGE_STDIO,
84 // [SYS_minherit] = PLEDGE_STDIO,
85 [SYS_mmap] = PLEDGE_STDIO,
86 [SYS_mprotect] = PLEDGE_STDIO,
87 // [SYS_mquery] = PLEDGE_STDIO,
88 [SYS_munmap] = PLEDGE_STDIO,
89 [SYS_msync] = PLEDGE_STDIO,
90 // [SYS_break] = PLEDGE_STDIO,
92 [SYS_umask] = PLEDGE_STDIO,
94 /* read/write operations */
95 [SYS_read] = PLEDGE_STDIO,
96 [SYS_readv] = PLEDGE_STDIO,
97 // [SYS_pread] = PLEDGE_STDIO,
98 [SYS_preadv] = PLEDGE_STDIO,
99 [SYS_write] = PLEDGE_STDIO,
100 [SYS_writev] = PLEDGE_STDIO,
101 // [SYS_pwrite] = PLEDGE_STDIO,
102 [SYS_pwritev] = PLEDGE_STDIO,
103 [SYS_recvmsg] = PLEDGE_STDIO,
104 [SYS_recvfrom] = PLEDGE_STDIO | PLEDGE_YPACTIVE,
105 [SYS_ftruncate] = PLEDGE_STDIO,
106 [SYS_lseek] = PLEDGE_STDIO,
107 // [SYS_fpathconf] = PLEDGE_STDIO,
110 * Address selection required a network pledge ("inet",
113 [SYS_sendto] = PLEDGE_STDIO | PLEDGE_YPACTIVE,
116 * Address specification required a network pledge ("inet",
117 * "unix", "dns". SCM_RIGHTS requires "sendfd" or "recvfd".
119 [SYS_sendmsg] = PLEDGE_STDIO,
121 /* Common signal operations */
122 [SYS_nanosleep] = PLEDGE_STDIO,
123 [SYS_sigaltstack] = PLEDGE_STDIO,
124 // [SYS_sigprocmask] = PLEDGE_STDIO,
125 // [SYS_sigsuspend] = PLEDGE_STDIO,
126 // [SYS_sigaction] = PLEDGE_STDIO,
127 // [SYS_sigreturn] = PLEDGE_STDIO,
128 // [SYS_sigpending] = PLEDGE_STDIO,
129 [SYS_getitimer] = PLEDGE_STDIO,
130 [SYS_setitimer] = PLEDGE_STDIO,
133 * To support event driven programming.
135 [SYS_poll] = PLEDGE_STDIO,
136 [SYS_ppoll] = PLEDGE_STDIO,
137 // [SYS_kevent] = PLEDGE_STDIO,
138 // [SYS_kqueue] = PLEDGE_STDIO,
139 [SYS_select] = PLEDGE_STDIO,
140 // [SYS_pselect] = PLEDGE_STDIO,
141 [SYS_pselect6] = PLEDGE_STDIO,
142 [SYS_epoll_create] = PLEDGE_STDIO,
143 [SYS_epoll_create1] = PLEDGE_STDIO,
144 [SYS_epoll_ctl] = PLEDGE_STDIO,
145 [SYS_epoll_pwait] = PLEDGE_STDIO,
146 [SYS_epoll_wait] = PLEDGE_STDIO,
147 [SYS_eventfd] = PLEDGE_STDIO,
148 [SYS_eventfd2] = PLEDGE_STDIO,
150 [SYS_fstat] = PLEDGE_STDIO,
151 [SYS_fsync] = PLEDGE_STDIO,
153 [SYS_setsockopt] = PLEDGE_STDIO, /* narrow whitelist */
154 [SYS_getsockopt] = PLEDGE_STDIO, /* narrow whitelist */
156 /* F_SETOWN requires PLEDGE_PROC */
157 [SYS_fcntl] = PLEDGE_STDIO,
159 [SYS_close] = PLEDGE_STDIO,
160 [SYS_dup] = PLEDGE_STDIO,
161 [SYS_dup2] = PLEDGE_STDIO,
162 [SYS_dup3] = PLEDGE_STDIO,
163 // [SYS_closefrom] = PLEDGE_STDIO,
164 [SYS_shutdown] = PLEDGE_STDIO,
165 [SYS_fchdir] = PLEDGE_STDIO, /* XXX consider tightening */
167 [SYS_pipe] = PLEDGE_STDIO,
168 [SYS_pipe2] = PLEDGE_STDIO,
169 [SYS_socketpair] = PLEDGE_STDIO,
171 [SYS_wait4] = PLEDGE_STDIO,
174 * Can kill self with "stdio". Killing another pid
177 // [SYS_o58_kill] = PLEDGE_STDIO,
178 [SYS_kill] = PLEDGE_STDIO,
181 * FIONREAD/FIONBIO for "stdio"
182 * A few non-tty ioctl available using "ioctl"
183 * tty-centric ioctl available using "tty"
185 [SYS_ioctl] = PLEDGE_STDIO,
188 * Path access/creation calls encounter many extensive
189 * checks are done during namei()
191 [SYS_open] = PLEDGE_STDIO,
192 [SYS_stat] = PLEDGE_STDIO,
193 [SYS_access] = PLEDGE_STDIO,
194 [SYS_readlink] = PLEDGE_STDIO,
196 // [SYS_adjtime] = PLEDGE_STDIO, /* setting requires "settime" */
197 // [SYS_adjfreq] = PLEDGE_SETTIME,
198 [SYS_settimeofday] = PLEDGE_SETTIME,
201 * Needed by threaded programs
202 * XXX should we have a new "threads"?
204 // [SYS___tfork] = PLEDGE_STDIO,
205 [SYS_sched_yield] = PLEDGE_STDIO,
206 // [SYS___thrsleep] = PLEDGE_STDIO,
207 // [SYS___thrwakeup] = PLEDGE_STDIO,
208 // [SYS___threxit] = PLEDGE_STDIO,
209 // [SYS___thrsigdivert] = PLEDGE_STDIO,
211 [SYS_fork] = PLEDGE_PROC,
212 [SYS_vfork] = PLEDGE_PROC,
213 [SYS_setpgid] = PLEDGE_PROC,
214 [SYS_setsid] = PLEDGE_PROC,
216 [SYS_setrlimit] = PLEDGE_PROC | PLEDGE_ID,
217 [SYS_getpriority] = PLEDGE_PROC | PLEDGE_ID,
219 [SYS_setpriority] = PLEDGE_PROC | PLEDGE_ID,
221 [SYS_setuid] = PLEDGE_ID,
222 // [SYS_seteuid] = PLEDGE_ID,
223 [SYS_setreuid] = PLEDGE_ID,
224 [SYS_setresuid] = PLEDGE_ID,
225 [SYS_setgid] = PLEDGE_ID,
226 // [SYS_setegid] = PLEDGE_ID,
227 [SYS_setregid] = PLEDGE_ID,
228 [SYS_setresgid] = PLEDGE_ID,
229 [SYS_setgroups] = PLEDGE_ID,
230 // [SYS_setlogin] = PLEDGE_ID,
232 [SYS_execve] = PLEDGE_EXEC,
234 [SYS_chdir] = PLEDGE_RPATH,
235 [SYS_openat] = PLEDGE_RPATH | PLEDGE_WPATH,
236 // [SYS_fstatat] = PLEDGE_RPATH | PLEDGE_WPATH,
237 [SYS_newfstatat] = PLEDGE_RPATH | PLEDGE_WPATH,
238 [SYS_faccessat] = PLEDGE_RPATH | PLEDGE_WPATH,
239 [SYS_readlinkat] = PLEDGE_RPATH | PLEDGE_WPATH,
240 [SYS_lstat] = PLEDGE_RPATH | PLEDGE_WPATH | PLEDGE_TMPPATH,
241 [SYS_truncate] = PLEDGE_WPATH,
242 [SYS_rename] = PLEDGE_CPATH,
243 [SYS_rmdir] = PLEDGE_CPATH,
244 [SYS_renameat] = PLEDGE_CPATH,
245 [SYS_link] = PLEDGE_CPATH,
246 [SYS_linkat] = PLEDGE_CPATH,
247 [SYS_symlink] = PLEDGE_CPATH,
248 [SYS_unlink] = PLEDGE_CPATH | PLEDGE_TMPPATH,
249 [SYS_unlinkat] = PLEDGE_CPATH,
250 [SYS_mkdir] = PLEDGE_CPATH,
251 [SYS_mkdirat] = PLEDGE_CPATH,
253 // [SYS_mkfifo] = PLEDGE_DPATH,
254 [SYS_mknod] = PLEDGE_DPATH,
256 [SYS_chroot] = PLEDGE_ID, /* also requires PLEDGE_PROC */
258 // [SYS_revoke] = PLEDGE_TTY, /* also requires PLEDGE_RPATH */
261 * Classify as RPATH|WPATH, because of path information leakage.
262 * WPATH due to unknown use of mk*temp(3) on non-/tmp paths..
264 // [SYS___getcwd] = PLEDGE_RPATH | PLEDGE_WPATH,
265 [SYS_getcwd] = PLEDGE_RPATH | PLEDGE_WPATH,
267 /* Classify as RPATH, because these leak path information */
268 [SYS_getdents] = PLEDGE_RPATH,
269 // [SYS_getfsstat] = PLEDGE_RPATH,
270 [SYS_statfs] = PLEDGE_RPATH,
271 [SYS_fstatfs] = PLEDGE_RPATH,
272 // [SYS_pathconf] = PLEDGE_RPATH,
274 [SYS_utimes] = PLEDGE_FATTR,
275 // [SYS_futimes] = PLEDGE_FATTR,
276 [SYS_futimesat] = PLEDGE_FATTR,
277 [SYS_utimensat] = PLEDGE_FATTR,
278 // [SYS_futimens] = PLEDGE_FATTR,
279 [SYS_chmod] = PLEDGE_FATTR,
280 [SYS_fchmod] = PLEDGE_FATTR,
281 [SYS_fchmodat] = PLEDGE_FATTR,
282 // [SYS_chflags] = PLEDGE_FATTR,
283 //[SYS_chflagsat] = PLEDGE_FATTR,
284 // [SYS_fchflags] = PLEDGE_FATTR,
285 [SYS_chown] = PLEDGE_FATTR,
286 [SYS_fchownat] = PLEDGE_FATTR,
287 [SYS_lchown] = PLEDGE_FATTR,
288 [SYS_fchown] = PLEDGE_FATTR,
290 [SYS_socket] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YPACTIVE,
291 [SYS_connect] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YPACTIVE,
292 [SYS_bind] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YPACTIVE,
293 [SYS_getsockname] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YPACTIVE,
295 [SYS_listen] = PLEDGE_INET | PLEDGE_UNIX,
296 [SYS_accept4] = PLEDGE_INET | PLEDGE_UNIX,
297 [SYS_accept] = PLEDGE_INET | PLEDGE_UNIX,
298 [SYS_getpeername] = PLEDGE_INET | PLEDGE_UNIX,
300 [SYS_flock] = PLEDGE_FLOCK | PLEDGE_YPACTIVE,
302 // [SYS_swapctl] = PLEDGE_VMINFO, /* XXX should limit to "get" operations */
306 static const struct {
310 { "audio", PLEDGE_AUDIO },
311 { "cpath", PLEDGE_CPATH },
312 { "disklabel", PLEDGE_DISKLABEL },
313 { "dns", PLEDGE_DNS },
314 { "dpath", PLEDGE_DPATH },
315 { "drm", PLEDGE_DRM },
316 { "exec", PLEDGE_EXEC },
317 { "fattr", PLEDGE_FATTR },
318 { "flock", PLEDGE_FLOCK },
319 { "getpw", PLEDGE_GETPW },
321 { "inet", PLEDGE_INET },
322 { "ioctl", PLEDGE_IOCTL },
323 { "mcast", PLEDGE_MCAST },
325 { "proc", PLEDGE_PROC },
326 { "prot_exec", PLEDGE_PROTEXEC },
328 { "recvfd", PLEDGE_RECVFD },
329 { "route", PLEDGE_ROUTE },
330 { "rpath", PLEDGE_RPATH },
331 { "sendfd", PLEDGE_SENDFD },
332 { "settime", PLEDGE_SETTIME },
333 { "stdio", PLEDGE_STDIO },
334 { "tmppath", PLEDGE_TMPPATH },
335 { "tty", PLEDGE_TTY },
336 { "unix", PLEDGE_UNIX },
337 { "vminfo", PLEDGE_VMINFO },
338 { "vmm", PLEDGE_VMM },
339 { "wpath", PLEDGE_WPATH },
342 scmp_filter_ctx scmp_ctx = NULL;
344 /* bsearch over pledgereq. return flags value if found, 0 else */
346 pledgereq_flags(const char *req_name)
348 int base = 0, cmp, i, lim;
350 for (lim = nitems(pledgereq); lim != 0; lim >>= 1) {
351 i = base + (lim >> 1);
352 cmp = strcmp(req_name, pledgereq[i].name);
354 return (pledgereq[i].flags);
355 if (cmp > 0) { /* not found before, move right */
358 } /* else move left */
363 /* whitelists syscalls returns -1 on error */
365 pledge(const char *promises, __UNUSED const char *paths[])
371 if (scmp_ctx == NULL) {
372 /* inintialize new seccomp whitelist */
373 if ((scmp_ctx = seccomp_init(SCMP_ACT_KILL)) == NULL)
374 err(1, "seccomp_init");
376 /* reset previous rules */
377 if (seccomp_reset(scmp_ctx, SCMP_ACT_KILL) < 0)
378 err(1, "seccomp_reset");
381 /* make flags from prmises string */
382 buf = strdup(promises);
383 for (p = strtok(buf, " "); p;
384 p = strtok(NULL, " ")) {
385 flags |= pledgereq_flags(p);
388 for (int i = 0; i < SYS_MAXSYSCALL; i++) {
389 /* skip not defined syscalls */
390 if (pledge_syscalls[i] == 0)
393 /* skip not matching syscalls */
394 if (!(pledge_syscalls[i] & flags))
397 /* seccomp whitelist syscall */
398 if((rv = seccomp_rule_add_exact(scmp_ctx, SCMP_ACT_ALLOW, i, 0)) != 0)
402 /* seccomp_export_pfc(scmp_ctx, STDERR_FILENO); */
408 /* seccomp_release(scmp_ctx); */
410 return (rv == 0 ? 0 : -1);