]> git.armaanb.net Git - opendoas.git/blob - libopenbsd/pledge-seccomp.c
Testing only seccomp pledge
[opendoas.git] / libopenbsd / pledge-seccomp.c
1 /*      $OpenBSD: kern_pledge.c,v 1.165 2016/04/28 14:25:08 beck Exp $  */
2
3 /*
4  * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
5  * Copyright (c) 2015 Theo de Raadt <deraadt@openbsd.org>
6  *
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.
10  *
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.
18  */
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <seccomp.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <sys/syscall.h>
27 #include <err.h>
28
29 #include "openbsd.h"
30 #include "pledge.h"
31
32 #define SYS_MAXSYSCALL 1000
33
34 /*
35  * Ordered in blocks starting with least risky and most required.
36  */
37 const uint64_t pledge_syscalls[SYS_MAXSYSCALL] = {
38         /*
39          * Minimum required
40          */
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 */
49
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,
73
74         /*
75          * Almost exclusively read-only, Very narrow subset.
76          * Use of "route", "inet", "dns", "ps", or "vminfo"
77          * expands access.
78          */
79         // [SYS_sysctl] = PLEDGE_STDIO,
80
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,
91
92         [SYS_umask] = PLEDGE_STDIO,
93
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,
108
109         /*
110          * Address selection required a network pledge ("inet",
111          * "unix", "dns".
112          */
113         [SYS_sendto] = PLEDGE_STDIO | PLEDGE_YPACTIVE,
114
115         /*
116          * Address specification required a network pledge ("inet",
117          * "unix", "dns".  SCM_RIGHTS requires "sendfd" or "recvfd".
118          */
119         [SYS_sendmsg] = PLEDGE_STDIO,
120
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,
131
132         /*
133          * To support event driven programming.
134          */
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,
149
150         [SYS_fstat] = PLEDGE_STDIO,
151         [SYS_fsync] = PLEDGE_STDIO,
152
153         [SYS_setsockopt] = PLEDGE_STDIO,        /* narrow whitelist */
154         [SYS_getsockopt] = PLEDGE_STDIO,        /* narrow whitelist */
155
156         /* F_SETOWN requires PLEDGE_PROC */
157         [SYS_fcntl] = PLEDGE_STDIO,
158
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 */
166
167         [SYS_pipe] = PLEDGE_STDIO,
168         [SYS_pipe2] = PLEDGE_STDIO,
169         [SYS_socketpair] = PLEDGE_STDIO,
170
171         [SYS_wait4] = PLEDGE_STDIO,
172
173         /*
174          * Can kill self with "stdio".  Killing another pid
175          * requires "proc"
176          */
177         // [SYS_o58_kill] = PLEDGE_STDIO,
178         [SYS_kill] = PLEDGE_STDIO,
179
180         /*
181          * FIONREAD/FIONBIO for "stdio"
182          * A few non-tty ioctl available using "ioctl"
183          * tty-centric ioctl available using "tty"
184          */
185         [SYS_ioctl] = PLEDGE_STDIO,
186
187         /*
188          * Path access/creation calls encounter many extensive
189          * checks are done during namei()
190          */
191         [SYS_open] = PLEDGE_STDIO,
192         [SYS_stat] = PLEDGE_STDIO,
193         [SYS_access] = PLEDGE_STDIO,
194         [SYS_readlink] = PLEDGE_STDIO,
195
196         // [SYS_adjtime] = PLEDGE_STDIO,   /* setting requires "settime" */
197         // [SYS_adjfreq] = PLEDGE_SETTIME,
198         [SYS_settimeofday] = PLEDGE_SETTIME,
199
200         /*
201          * Needed by threaded programs
202          * XXX should we have a new "threads"?
203          */
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,
210
211         [SYS_fork] = PLEDGE_PROC,
212         [SYS_vfork] = PLEDGE_PROC,
213         [SYS_setpgid] = PLEDGE_PROC,
214         [SYS_setsid] = PLEDGE_PROC,
215
216         [SYS_setrlimit] = PLEDGE_PROC | PLEDGE_ID,
217         [SYS_getpriority] = PLEDGE_PROC | PLEDGE_ID,
218
219         [SYS_setpriority] = PLEDGE_PROC | PLEDGE_ID,
220
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,
231
232         [SYS_execve] = PLEDGE_EXEC,
233
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,
252
253         // [SYS_mkfifo] = PLEDGE_DPATH,
254         [SYS_mknod] = PLEDGE_DPATH,
255
256         [SYS_chroot] = PLEDGE_ID,       /* also requires PLEDGE_PROC */
257
258         // [SYS_revoke] = PLEDGE_TTY,   /* also requires PLEDGE_RPATH */
259
260         /*
261          * Classify as RPATH|WPATH, because of path information leakage.
262          * WPATH due to unknown use of mk*temp(3) on non-/tmp paths..
263          */
264         // [SYS___getcwd] = PLEDGE_RPATH | PLEDGE_WPATH,
265         [SYS_getcwd] = PLEDGE_RPATH | PLEDGE_WPATH,
266
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,
273
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,
289
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,
294
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,
299
300         [SYS_flock] = PLEDGE_FLOCK | PLEDGE_YPACTIVE,
301
302         // [SYS_swapctl] = PLEDGE_VMINFO,       /* XXX should limit to "get" operations */
303 };
304
305
306 static const struct {
307         char *name;
308         int flags;
309 } pledgereq[] = {
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 },
320         { "id",                 PLEDGE_ID },
321         { "inet",               PLEDGE_INET },
322         { "ioctl",              PLEDGE_IOCTL },
323         { "mcast",              PLEDGE_MCAST },
324         { "pf",                 PLEDGE_PF },
325         { "proc",               PLEDGE_PROC },
326         { "prot_exec",          PLEDGE_PROTEXEC },
327         { "ps",                 PLEDGE_PS },
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 },
340 };
341
342 scmp_filter_ctx scmp_ctx = NULL;
343
344 /* bsearch over pledgereq. return flags value if found, 0 else */
345 static int
346 pledgereq_flags(const char *req_name)
347 {
348         int base = 0, cmp, i, lim;
349
350         for (lim = nitems(pledgereq); lim != 0; lim >>= 1) {
351                 i = base + (lim >> 1);
352                 cmp = strcmp(req_name, pledgereq[i].name);
353                 if (cmp == 0)
354                         return (pledgereq[i].flags);
355                 if (cmp > 0) { /* not found before, move right */
356                         base = i + 1;
357                         lim--;
358                 } /* else move left */
359         }
360         return (0);
361 }
362
363 /* whitelists syscalls returns -1 on error */
364 int
365 pledge(const char *promises, __UNUSED const char *paths[])
366 {
367         char *buf, *p;
368         int rv = 0;
369         uint64_t flags = 0;
370
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");
375         } else {
376                 /* reset previous rules */
377                 if (seccomp_reset(scmp_ctx, SCMP_ACT_KILL) < 0)
378                         err(1, "seccomp_reset");
379         }
380
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);
386         }
387
388         for (int i = 0; i < SYS_MAXSYSCALL; i++) {
389                 /* skip not defined syscalls */
390                 if (pledge_syscalls[i] == 0)
391                         continue;
392
393                 /* skip not matching syscalls */
394                 if (!(pledge_syscalls[i] & flags))
395                         continue;
396
397                 /* seccomp whitelist syscall */
398                 if((rv = seccomp_rule_add_exact(scmp_ctx, SCMP_ACT_ALLOW, i, 0)) != 0)
399                         goto out;
400         }
401
402         /* seccomp_export_pfc(scmp_ctx, STDERR_FILENO); */
403
404 out:
405         free(buf);
406         free(p);
407
408         /* seccomp_release(scmp_ctx); */
409
410         return (rv == 0 ? 0 : -1);
411 }