seccomp.c revision 354939
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.8 2019/02/24 18:12:04 christos Exp $")
31#endif	/* lint */
32
33#if HAVE_LIBSECCOMP
34#include <seccomp.h> /* libseccomp */
35#include <sys/prctl.h> /* prctl */
36#include <sys/socket.h>
37#include <fcntl.h>
38#include <stdlib.h>
39#include <errno.h>
40
41#define DENY_RULE(call) \
42    do \
43	if (seccomp_rule_add (ctx, SCMP_ACT_KILL, SCMP_SYS(call), 0) == -1) \
44	    goto out; \
45    while (/*CONSTCOND*/0)
46#define ALLOW_RULE(call) \
47    do \
48	if (seccomp_rule_add (ctx, SCMP_ACT_ALLOW, SCMP_SYS(call), 0) == -1) \
49	    goto out; \
50    while (/*CONSTCOND*/0)
51
52static scmp_filter_ctx ctx;
53
54
55int
56enable_sandbox_basic(void)
57{
58
59	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
60		return -1;
61
62	if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1)
63		return -1;
64
65	// initialize the filter
66	ctx = seccomp_init(SCMP_ACT_ALLOW);
67	if (ctx == NULL)
68	    return 1;
69
70	DENY_RULE(_sysctl);
71	DENY_RULE(acct);
72	DENY_RULE(add_key);
73	DENY_RULE(adjtimex);
74	DENY_RULE(chroot);
75	DENY_RULE(clock_adjtime);
76	DENY_RULE(create_module);
77	DENY_RULE(delete_module);
78	DENY_RULE(fanotify_init);
79	DENY_RULE(finit_module);
80	DENY_RULE(get_kernel_syms);
81	DENY_RULE(get_mempolicy);
82	DENY_RULE(init_module);
83	DENY_RULE(io_cancel);
84	DENY_RULE(io_destroy);
85	DENY_RULE(io_getevents);
86	DENY_RULE(io_setup);
87	DENY_RULE(io_submit);
88	DENY_RULE(ioperm);
89	DENY_RULE(iopl);
90	DENY_RULE(ioprio_set);
91	DENY_RULE(kcmp);
92#ifdef __NR_kexec_file_load
93	DENY_RULE(kexec_file_load);
94#endif
95	DENY_RULE(kexec_load);
96	DENY_RULE(keyctl);
97	DENY_RULE(lookup_dcookie);
98	DENY_RULE(mbind);
99	DENY_RULE(nfsservctl);
100	DENY_RULE(migrate_pages);
101	DENY_RULE(modify_ldt);
102	DENY_RULE(mount);
103	DENY_RULE(move_pages);
104	DENY_RULE(name_to_handle_at);
105	DENY_RULE(open_by_handle_at);
106	DENY_RULE(perf_event_open);
107	DENY_RULE(pivot_root);
108	DENY_RULE(process_vm_readv);
109	DENY_RULE(process_vm_writev);
110	DENY_RULE(ptrace);
111	DENY_RULE(reboot);
112	DENY_RULE(remap_file_pages);
113	DENY_RULE(request_key);
114	DENY_RULE(set_mempolicy);
115	DENY_RULE(swapoff);
116	DENY_RULE(swapon);
117	DENY_RULE(sysfs);
118	DENY_RULE(syslog);
119	DENY_RULE(tuxcall);
120	DENY_RULE(umount2);
121	DENY_RULE(uselib);
122	DENY_RULE(vmsplice);
123
124	// blocking dangerous syscalls that file should not need
125	DENY_RULE (execve);
126	DENY_RULE (socket);
127	// ...
128
129
130	// applying filter...
131	if (seccomp_load (ctx) == -1)
132		goto out;
133	// free ctx after the filter has been loaded into the kernel
134	seccomp_release(ctx);
135	return 0;
136
137out:
138	seccomp_release(ctx);
139	return -1;
140}
141
142
143int
144enable_sandbox_full(void)
145{
146
147	// prevent child processes from getting more priv e.g. via setuid,
148	// capabilities, ...
149	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
150		return -1;
151
152	if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1)
153		return -1;
154
155	// initialize the filter
156	ctx = seccomp_init(SCMP_ACT_KILL);
157	if (ctx == NULL)
158		return -1;
159
160	ALLOW_RULE(access);
161	ALLOW_RULE(brk);
162	ALLOW_RULE(close);
163	ALLOW_RULE(dup2);
164	ALLOW_RULE(exit);
165	ALLOW_RULE(exit_group);
166	ALLOW_RULE(fcntl);
167 	ALLOW_RULE(fcntl64);
168	ALLOW_RULE(fstat);
169 	ALLOW_RULE(fstat64);
170	ALLOW_RULE(getdents);
171#ifdef __NR_getdents64
172	ALLOW_RULE(getdents64);
173#endif
174	ALLOW_RULE(ioctl);
175	ALLOW_RULE(lseek);
176 	ALLOW_RULE(_llseek);
177	ALLOW_RULE(lstat);
178 	ALLOW_RULE(lstat64);
179	ALLOW_RULE(madvise);
180	ALLOW_RULE(mmap);
181 	ALLOW_RULE(mmap2);
182	ALLOW_RULE(mprotect);
183	ALLOW_RULE(mremap);
184	ALLOW_RULE(munmap);
185#ifdef __NR_newfstatat
186	ALLOW_RULE(newfstatat);
187#endif
188	ALLOW_RULE(open);
189	ALLOW_RULE(openat);
190	ALLOW_RULE(pread64);
191	ALLOW_RULE(read);
192	ALLOW_RULE(readlink);
193	ALLOW_RULE(rt_sigaction);
194	ALLOW_RULE(rt_sigprocmask);
195	ALLOW_RULE(rt_sigreturn);
196	ALLOW_RULE(select);
197	ALLOW_RULE(stat);
198	ALLOW_RULE(stat64);
199	ALLOW_RULE(sysinfo);
200	ALLOW_RULE(unlink);
201	ALLOW_RULE(write);
202
203
204#if 0
205	// needed by valgrind
206	ALLOW_RULE(gettid);
207	ALLOW_RULE(getpid);
208	ALLOW_RULE(rt_sigtimedwait);
209#endif
210
211#if 0
212	 /* special restrictions for socket, only allow AF_UNIX/AF_LOCAL */
213	 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1,
214	     SCMP_CMP(0, SCMP_CMP_EQ, AF_UNIX)) == -1)
215	 	goto out;
216
217	 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 1,
218	     SCMP_CMP(0, SCMP_CMP_EQ, AF_LOCAL)) == -1)
219	 	goto out;
220
221
222	 /* special restrictions for open, prevent opening files for writing */
223	 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 1,
224	     SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY | O_RDWR, 0)) == -1)
225	 	goto out;
226
227	 if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1,
228	     SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_WRONLY, O_WRONLY)) == -1)
229	 	goto out;
230
231	 if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(open), 1,
232	     SCMP_CMP(1, SCMP_CMP_MASKED_EQ, O_RDWR, O_RDWR)) == -1)
233	 	goto out;
234
235
236	 /* allow stderr */
237	 if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 1,
238	     SCMP_CMP(0, SCMP_CMP_EQ, 2)) == -1)
239		 goto out;
240#endif
241
242	// applying filter...
243	if (seccomp_load(ctx) == -1)
244		goto out;
245	// free ctx after the filter has been loaded into the kernel
246	seccomp_release(ctx);
247	return 0;
248
249out:
250	// something went wrong
251	seccomp_release(ctx);
252	return -1;
253}
254#endif
255