seccomp.c revision 362844
1/*
2 * Redistribution and use in source and binary forms, with or without
3 * modification, are permitted provided that the following conditions
4 * are met:
5 * 1. Redistributions of source code must retain the above copyright
6 *    notice immediately at the beginning of the file, without modification,
7 *    this list of conditions, and the following disclaimer.
8 * 2. Redistributions in binary form must reproduce the above copyright
9 *    notice, this list of conditions and the following disclaimer in the
10 *    documentation and/or other materials provided with the distribution.
11 *
12 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
16 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22 * SUCH DAMAGE.
23 */
24/*
25 * libseccomp hooks.
26 */
27#include "file.h"
28
29#ifndef	lint
30FILE_RCSID("@(#)$File: seccomp.c,v 1.15 2020/05/30 23:56:26 christos Exp $")
31#endif	/* lint */
32
33#if HAVE_LIBSECCOMP
34#include <seccomp.h> /* libseccomp */
35#include <sys/prctl.h> /* prctl */
36#include <sys/ioctl.h>
37#include <sys/socket.h>
38#include <fcntl.h>
39#include <stdlib.h>
40#include <errno.h>
41
42#define DENY_RULE(call) \
43    do \
44	if (seccomp_rule_add (ctx, SCMP_ACT_KILL, SCMP_SYS(call), 0) == -1) \
45	    goto out; \
46    while (/*CONSTCOND*/0)
47#define ALLOW_RULE(call) \
48    do \
49	if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(call), 0) == -1) \
50	    goto out; \
51    while (/*CONSTCOND*/0)
52
53#define ALLOW_IOCTL_RULE(param) \
54    do \
55	if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1, \
56	    SCMP_CMP(1, SCMP_CMP_EQ, param)) == -1) \
57		goto out; \
58    while (/*CONSTCOND*/0)
59
60static scmp_filter_ctx ctx;
61
62int
63enable_sandbox_basic(void)
64{
65
66	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
67		return -1;
68
69	if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1)
70		return -1;
71
72	// initialize the filter
73	ctx = seccomp_init(SCMP_ACT_ALLOW);
74	if (ctx == NULL)
75	    return 1;
76
77	DENY_RULE(_sysctl);
78	DENY_RULE(acct);
79	DENY_RULE(add_key);
80	DENY_RULE(adjtimex);
81	DENY_RULE(chroot);
82	DENY_RULE(clock_adjtime);
83	DENY_RULE(create_module);
84	DENY_RULE(delete_module);
85	DENY_RULE(fanotify_init);
86	DENY_RULE(finit_module);
87	DENY_RULE(get_kernel_syms);
88	DENY_RULE(get_mempolicy);
89	DENY_RULE(init_module);
90	DENY_RULE(io_cancel);
91	DENY_RULE(io_destroy);
92	DENY_RULE(io_getevents);
93	DENY_RULE(io_setup);
94	DENY_RULE(io_submit);
95	DENY_RULE(ioperm);
96	DENY_RULE(iopl);
97	DENY_RULE(ioprio_set);
98	DENY_RULE(kcmp);
99#ifdef __NR_kexec_file_load
100	DENY_RULE(kexec_file_load);
101#endif
102	DENY_RULE(kexec_load);
103	DENY_RULE(keyctl);
104	DENY_RULE(lookup_dcookie);
105	DENY_RULE(mbind);
106	DENY_RULE(nfsservctl);
107	DENY_RULE(migrate_pages);
108	DENY_RULE(modify_ldt);
109	DENY_RULE(mount);
110	DENY_RULE(move_pages);
111	DENY_RULE(name_to_handle_at);
112	DENY_RULE(open_by_handle_at);
113	DENY_RULE(perf_event_open);
114	DENY_RULE(pivot_root);
115	DENY_RULE(process_vm_readv);
116	DENY_RULE(process_vm_writev);
117	DENY_RULE(ptrace);
118	DENY_RULE(reboot);
119	DENY_RULE(remap_file_pages);
120	DENY_RULE(request_key);
121	DENY_RULE(set_mempolicy);
122	DENY_RULE(swapoff);
123	DENY_RULE(swapon);
124	DENY_RULE(sysfs);
125	DENY_RULE(syslog);
126	DENY_RULE(tuxcall);
127	DENY_RULE(umount2);
128	DENY_RULE(uselib);
129	DENY_RULE(vmsplice);
130
131	// blocking dangerous syscalls that file should not need
132	DENY_RULE (execve);
133	DENY_RULE (socket);
134	// ...
135
136
137	// applying filter...
138	if (seccomp_load (ctx) == -1)
139		goto out;
140	// free ctx after the filter has been loaded into the kernel
141	seccomp_release(ctx);
142	return 0;
143
144out:
145	seccomp_release(ctx);
146	return -1;
147}
148
149
150int
151enable_sandbox_full(void)
152{
153
154	// prevent child processes from getting more priv e.g. via setuid,
155	// capabilities, ...
156	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
157		return -1;
158
159	if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1)
160		return -1;
161
162	// initialize the filter
163	ctx = seccomp_init(SCMP_ACT_KILL);
164	if (ctx == NULL)
165		return -1;
166
167	ALLOW_RULE(access);
168	ALLOW_RULE(brk);
169	ALLOW_RULE(close);
170	ALLOW_RULE(dup2);
171	ALLOW_RULE(exit);
172	ALLOW_RULE(exit_group);
173	ALLOW_RULE(fcntl);
174 	ALLOW_RULE(fcntl64);
175	ALLOW_RULE(fstat);
176 	ALLOW_RULE(fstat64);
177#ifdef XZLIBSUPPORT
178	ALLOW_RULE(futex);
179#endif
180	ALLOW_RULE(getdents);
181#ifdef __NR_getdents64
182	ALLOW_RULE(getdents64);
183#endif
184#ifdef FIONREAD
185	// called in src/compress.c under sread
186	ALLOW_IOCTL_RULE(FIONREAD);
187#endif
188#ifdef TIOCGWINSZ
189	// musl libc may call ioctl TIOCGWINSZ on stdout
190	ALLOW_IOCTL_RULE(TIOCGWINSZ);
191#endif
192#ifdef TCGETS
193	// glibc may call ioctl TCGETS on stdout on physical terminal
194	ALLOW_IOCTL_RULE(TCGETS);
195#endif
196	ALLOW_RULE(lseek);
197 	ALLOW_RULE(_llseek);
198	ALLOW_RULE(lstat);
199 	ALLOW_RULE(lstat64);
200	ALLOW_RULE(madvise);
201	ALLOW_RULE(mmap);
202 	ALLOW_RULE(mmap2);
203	ALLOW_RULE(mprotect);
204	ALLOW_RULE(mremap);
205	ALLOW_RULE(munmap);
206#ifdef __NR_newfstatat
207	ALLOW_RULE(newfstatat);
208#endif
209	ALLOW_RULE(open);
210	ALLOW_RULE(openat);
211	ALLOW_RULE(pread64);
212	ALLOW_RULE(read);
213	ALLOW_RULE(readlink);
214#ifdef __NR_readlinkat
215	ALLOW_RULE(readlinkat);
216#endif
217	ALLOW_RULE(rt_sigaction);
218	ALLOW_RULE(rt_sigprocmask);
219	ALLOW_RULE(rt_sigreturn);
220	ALLOW_RULE(select);
221	ALLOW_RULE(stat);
222	ALLOW_RULE(stat64);
223	ALLOW_RULE(sysinfo);
224	ALLOW_RULE(umask);	// Used in file_pipe2file()
225	ALLOW_RULE(getpid);	// Used by glibc in file_pipe2file()
226	ALLOW_RULE(unlink);
227	ALLOW_RULE(write);
228
229
230#if 0
231	// needed by valgrind
232	ALLOW_RULE(gettid);
233	ALLOW_RULE(rt_sigtimedwait);
234#endif
235
236#if 0
237	 /* special restrictions for socket, only allow AF_UNIX/AF_LOCAL */
238	 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1,
239	     SCMP_CMP(0, SCMP_CMP_EQ, AF_UNIX)) == -1)
240	 	goto out;
241
242	 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1,
243	     SCMP_CMP(0, SCMP_CMP_EQ, AF_LOCAL)) == -1)
244	 	goto out;
245
246
247	 /* special restrictions for open, prevent opening files for writing */
248	 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 1,
249	     SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY | O_RDWR, 0)) == -1)
250	 	goto out;
251
252	 if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1,
253	     SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY)) == -1)
254	 	goto out;
255
256	 if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1,
257	     SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR)) == -1)
258	 	goto out;
259
260
261	 /* allow stderr */
262	 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1,
263	     SCMP_CMP(0, SCMP_CMP_EQ, 2)) == -1)
264		 goto out;
265#endif
266
267	// applying filter...
268	if (seccomp_load(ctx) == -1)
269		goto out;
270	// free ctx after the filter has been loaded into the kernel
271	seccomp_release(ctx);
272	return 0;
273
274out:
275	// something went wrong
276	seccomp_release(ctx);
277	return -1;
278}
279#endif
280