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