1 /*
2  * Generate the bpf rules ahead of time to speed up runtime.
3  *
4  * Copyright 2015 Gentoo Foundation
5  * Distributed under the terms of the GNU General Public License v2
6  *
7  * Copyright 2015 Mike Frysinger  - <vapier@gentoo.org>
8  */
9 
10 const char argv0[] = "seccomp-bpf";
11 
12 #include <err.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <sys/mman.h>
17 #include <sys/types.h>
18 
19 #include <seccomp.h>
20 
21 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
22 
23 static const struct {
24 	const char *name;
25 	uint32_t arch;
26 	const char *ifdef;
27 } gen_seccomp_arches[] = {
28 #define A(arch, ifdef) { #arch, SCMP_ARCH_##arch, ifdef }
29 	A(AARCH64,     "defined(__aarch64__)"),
30 	A(ARM,         "defined(__arm__)"),
31 	A(MIPS,        "defined(__mips__) && defined(__MIPSEB__) && (_MIPS_SIM == _ABIO32)"),
32 	A(MIPS64,      "defined(__mips__) && defined(__MIPSEB__) && (_MIPS_SIM == _ABI64)"),
33 	A(MIPS64N32,   "defined(__mips__) && defined(__MIPSEB__) && (_MIPS_SIM == _ABIN32)"),
34 	A(MIPSEL,      "defined(__mips__) && defined(__MIPSEL__) && (_MIPS_SIM == _ABIO32)"),
35 	A(MIPSEL64,    "defined(__mips__) && defined(__MIPSEL__) && (_MIPS_SIM == _ABI64)"),
36 	A(MIPSEL64N32, "defined(__mips__) && defined(__MIPSEL__) && (_MIPS_SIM == _ABIN32)"),
37 	A(PARISC,      "defined(__hppa__) && !defined(__hppa64__)"),
38 	A(PARISC64,    "defined(__hppa__) &&  defined(__hppa64__)"),
39 	A(PPC,         "defined(__powerpc__) && !defined(__powerpc64__) &&  defined(__BIG_ENDIAN__)"),
40 	A(PPC64,       "defined(__powerpc__) &&  defined(__powerpc64__) &&  defined(__BIG_ENDIAN__)"),
41 	A(PPC64LE,     "defined(__powerpc__) &&  defined(__powerpc64__) && !defined(__BIG_ENDIAN__)"),
42 	A(RISCV64,     "defined(__riscv) && __riscv_xlen == 64"),
43 	A(S390,        "defined(__s390__) && !defined(__s390x__)"),
44 	A(S390X,       "defined(__s390__) &&  defined(__s390x__)"),
45 	A(X86,         "defined(__i386__)"),
46 	A(X32,         "defined(__x86_64__) &&  defined(__ILP32__)"),
47 	A(X86_64,      "defined(__x86_64__) && !defined(__ILP32__)"),
48 #undef A
49 };
50 
51 /* Simple helper to add all of the syscalls in an array. */
gen_seccomp_rules_add(scmp_filter_ctx ctx,int syscalls[],size_t num)52 static int gen_seccomp_rules_add(scmp_filter_ctx ctx, int syscalls[], size_t num)
53 {
54 	static uint8_t prio;
55 	size_t i;
56 	for (i = 0; i < num; ++i) {
57 		if (seccomp_syscall_priority(ctx, syscalls[i], prio++) < 0) {
58 			warn("seccomp_syscall_priority failed");
59 			return -1;
60 		}
61 		if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls[i], 0) < 0) {
62 			warn("seccomp_rule_add failed");
63 			return -1;
64 		}
65 	}
66 	return 0;
67 }
68 #define gen_seccomp_rules_add(ctx, syscalls) gen_seccomp_rules_add(ctx, syscalls, ARRAY_SIZE(syscalls))
69 
gen_seccomp_dump(scmp_filter_ctx ctx,const char * name)70 static void gen_seccomp_dump(scmp_filter_ctx ctx, const char *name)
71 {
72 	unsigned char buf[32768 * 8];
73 	ssize_t i, len;
74 	int fd;
75 
76 	fd = memfd_create("bpf", MFD_CLOEXEC);
77 	if (fd < 0)
78 		err(1, "memfd_create failed");
79 	if (seccomp_export_bpf(ctx, fd) < 0)
80 		err(1, "seccomp_export_bpf_mem failed");
81 	if (lseek(fd, 0, SEEK_SET) != 0)
82 		err(1, "seek failed");
83 	len = read(fd, buf, sizeof(buf));
84 	if (len <= 0)
85 		err(1, "read failed");
86 
87 	printf("static const unsigned char seccomp_bpf_blks_%s[] = {\n\t", name);
88 	for (i = 0; i < len; ++i)
89 		printf("%u,", buf[i]);
90 	printf("\n};\n");
91 }
92 
gen_seccomp_program(const char * name)93 static void gen_seccomp_program(const char *name)
94 {
95 	printf(
96 		"static const seccomp_bpf_program_t seccomp_bpf_program_%s = {\n"
97 		"	.cnt = sizeof(seccomp_bpf_blks_%s) / 8,\n"
98 		"	.bpf = seccomp_bpf_blks_%s,\n"
99 		"};\n", name, name, name);
100 }
101 
main(void)102 int main(void)
103 {
104 	/* Order determines priority (first == lowest prio).  */
105 	int base_syscalls[] = {
106 		/* We write the most w/scanelf.  */
107 		SCMP_SYS(write),
108 		SCMP_SYS(writev),
109 		SCMP_SYS(pwrite64),
110 		SCMP_SYS(pwritev),
111 
112 		/* Then the stat family of functions.  */
113 		SCMP_SYS(newfstatat),
114 		SCMP_SYS(fstat),
115 		SCMP_SYS(fstat64),
116 		SCMP_SYS(fstatat64),
117 		SCMP_SYS(lstat),
118 		SCMP_SYS(lstat64),
119 		SCMP_SYS(stat),
120 		SCMP_SYS(stat64),
121 		SCMP_SYS(statx),
122 
123 		/* Then the fd close func.  */
124 		SCMP_SYS(close),
125 
126 		/* Then fd open family of functions.  */
127 		SCMP_SYS(open),
128 		SCMP_SYS(openat),
129 
130 		/* Then the memory mapping functions.  */
131 		SCMP_SYS(mmap),
132 		SCMP_SYS(mmap2),
133 		SCMP_SYS(munmap),
134 
135 		/* Then the directory reading functions.  */
136 		SCMP_SYS(getdents),
137 		SCMP_SYS(getdents64),
138 
139 		/* Then the file reading functions.  */
140 		SCMP_SYS(pread64),
141 		SCMP_SYS(read),
142 		SCMP_SYS(readv),
143 		SCMP_SYS(preadv),
144 
145 		/* Then the fd manipulation functions.  */
146 		SCMP_SYS(fcntl),
147 		SCMP_SYS(fcntl64),
148 
149 		/* After this point, just sort the list alphabetically.  */
150 		SCMP_SYS(access),
151 		SCMP_SYS(brk),
152 		SCMP_SYS(capget),
153 		SCMP_SYS(chdir),
154 		SCMP_SYS(dup),
155 		SCMP_SYS(dup2),
156 		SCMP_SYS(dup3),
157 		SCMP_SYS(exit),
158 		SCMP_SYS(exit_group),
159 		SCMP_SYS(faccessat),
160 #ifndef __SNR_faccessat2
161 /* faccessat2 is not yet defined in libseccomp-2.5.1 */
162 # define __SNR_faccessat2 __NR_faccessat2
163 #endif
164 		SCMP_SYS(faccessat2),
165 		SCMP_SYS(fchdir),
166 		SCMP_SYS(getpid),
167 		SCMP_SYS(gettid),
168 		SCMP_SYS(ioctl),
169 		SCMP_SYS(lseek),
170 		SCMP_SYS(_llseek),
171 		SCMP_SYS(mprotect),
172 
173 		/* Syscalls listed because of compiler settings.  */
174 		SCMP_SYS(futex),
175 
176 		/* Syscalls listed because of sandbox.  */
177 		SCMP_SYS(readlink),
178 		SCMP_SYS(readlinkat),
179 		SCMP_SYS(getcwd),
180 
181 		/* Syscalls listed because of fakeroot.  */
182 		SCMP_SYS(msgget),
183 		SCMP_SYS(msgrcv),
184 		SCMP_SYS(msgsnd),
185 		SCMP_SYS(semget),
186 		SCMP_SYS(semop),
187 		SCMP_SYS(semtimedop),
188 		/*
189 		 * Some targets (e.g. ppc & i386) implement the above functions
190 		 * as ipc() subcalls.  #675378
191 		 */
192 		SCMP_SYS(ipc),
193 
194 		/* glibc-2.34+ uses it as part of mem alloc functions. */
195 		SCMP_SYS(getrandom),
196 	};
197 	int fork_syscalls[] = {
198 		SCMP_SYS(clone),
199 		SCMP_SYS(execve),
200 		SCMP_SYS(fork),
201 		SCMP_SYS(rt_sigaction),
202 		SCMP_SYS(rt_sigprocmask),
203 		SCMP_SYS(unshare),
204 		SCMP_SYS(vfork),
205 		SCMP_SYS(wait4),
206 		SCMP_SYS(waitid),
207 		SCMP_SYS(waitpid),
208 	};
209 
210 	/* TODO: Handle debug and KILL vs TRAP. */
211 
212 	scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);
213 	if (!ctx)
214 		err(1, "seccomp_init failed");
215 
216 	printf("/* AUTO GENERATED FILE. To regenerate run:\n");
217 	printf(" *   $ $EDITOR seccomp-bpf.c\n");
218 	printf(" *   $ make seccomp-bpf.h\n");
219 	printf(" * See seccomp-bpf.c for details. */\n");
220 	printf("#undef SECCOMP_BPF_AVAILABLE\n");
221 
222 	if (seccomp_arch_remove(ctx, seccomp_arch_native()) < 0)
223 		err(1, "seccomp_arch_remove failed");
224 
225 	for (size_t i = 0; i < ARRAY_SIZE(gen_seccomp_arches); ++i) {
226 		uint32_t arch = gen_seccomp_arches[i].arch;
227 
228 		seccomp_reset(ctx, SCMP_ACT_KILL);
229 
230 		if (arch != seccomp_arch_native()) {
231 			if (seccomp_arch_remove(ctx, seccomp_arch_native()) < 0)
232 				err(1, "seccomp_arch_remove failed");
233 			if (seccomp_arch_add(ctx, arch) < 0)
234 				err(1, "seccomp_arch_add failed");
235 		}
236 
237 		printf("\n#if %s\n", gen_seccomp_arches[i].ifdef);
238 		printf("/* %s */\n", gen_seccomp_arches[i].name);
239 		printf("#define SECCOMP_BPF_AVAILABLE\n");
240 
241 		if (gen_seccomp_rules_add(ctx, base_syscalls) < 0)
242 			err(1, "seccomp_rules_add failed");
243 		gen_seccomp_dump(ctx, "base");
244 
245 		if (gen_seccomp_rules_add(ctx, fork_syscalls) < 0)
246 			err(1, "seccomp_rules_add failed");
247 		gen_seccomp_dump(ctx, "fork");
248 
249 		if (0) {
250 			printf("/*\n");
251 			fflush(stdout);
252 			seccomp_export_pfc(ctx, 1);
253 			fflush(stdout);
254 			printf("*/\n");
255 		}
256 
257 		printf("#endif\n");
258 	}
259 
260 	printf(
261 		"\n"
262 		"#ifdef SECCOMP_BPF_AVAILABLE\n"
263 		"typedef struct {\n"
264 		"	uint16_t cnt;\n"
265 		"	const void *bpf;\n"
266 		"} seccomp_bpf_program_t;\n");
267 	gen_seccomp_program("base");
268 	gen_seccomp_program("fork");
269 	printf("#endif\n");
270 
271 	seccomp_release(ctx);
272 
273 	return 0;
274 }
275