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