]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/seccomp.c
tree-wide: priority -> level
[mirror_lxc.git] / src / lxc / seccomp.c
1 /*
2 * lxc: linux Container library
3 *
4 * (C) Copyright Canonical, Inc. 2012
5 *
6 * Authors:
7 * Serge Hallyn <serge.hallyn@canonical.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #define _GNU_SOURCE
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <seccomp.h>
29 #include <sys/mount.h>
30 #include <sys/utsname.h>
31
32 #include "config.h"
33 #include "log.h"
34 #include "lxcseccomp.h"
35
36 lxc_log_define(lxc_seccomp, lxc);
37
38 static int parse_config_v1(FILE *f, struct lxc_conf *conf)
39 {
40 char line[1024];
41 int ret;
42
43 while (fgets(line, 1024, f)) {
44 int nr;
45 ret = sscanf(line, "%d", &nr);
46 if (ret != 1)
47 return -1;
48 ret = seccomp_rule_add(
49 #if HAVE_SCMP_FILTER_CTX
50 conf->seccomp_ctx,
51 #endif
52 SCMP_ACT_ALLOW, nr, 0);
53 if (ret < 0) {
54 ERROR("Failed loading allow rule for %d.", nr);
55 return ret;
56 }
57 }
58 return 0;
59 }
60
61 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
62 static void remove_trailing_newlines(char *l)
63 {
64 char *p = l;
65
66 while (*p)
67 p++;
68 while (--p >= l && *p == '\n')
69 *p = '\0';
70 }
71
72 static uint32_t get_v2_default_action(char *line)
73 {
74 uint32_t ret_action = -1;
75
76 while (*line == ' ')
77 line++;
78 // after 'whitelist' or 'blacklist' comes default behavior
79 if (strncmp(line, "kill", 4) == 0)
80 ret_action = SCMP_ACT_KILL;
81 else if (strncmp(line, "errno", 5) == 0) {
82 int e;
83 if (sscanf(line + 5, "%d", &e) != 1) {
84 ERROR("Bad errno value in %s.", line);
85 return -2;
86 }
87 ret_action = SCMP_ACT_ERRNO(e);
88 } else if (strncmp(line, "allow", 5) == 0)
89 ret_action = SCMP_ACT_ALLOW;
90 else if (strncmp(line, "trap", 4) == 0)
91 ret_action = SCMP_ACT_TRAP;
92 return ret_action;
93 }
94
95 static const char *get_action_name(uint32_t action)
96 {
97 // The upper 16 bits indicate the type of the seccomp action
98 switch(action & 0xffff0000){
99 case SCMP_ACT_KILL:
100 return "kill";
101 case SCMP_ACT_ALLOW:
102 return "allow";
103 case SCMP_ACT_TRAP:
104 return "trap";
105 case SCMP_ACT_ERRNO(0):
106 return "errno";
107 default:
108 return "invalid action";
109 }
110 }
111
112 static uint32_t get_and_clear_v2_action(char *line, uint32_t def_action)
113 {
114 char *p = strchr(line, ' ');
115 uint32_t ret;
116
117 if (!p)
118 return def_action;
119 *p = '\0';
120 p++;
121 while (*p == ' ')
122 p++;
123 if (!*p || *p == '#')
124 return def_action;
125 ret = get_v2_default_action(p);
126 switch(ret) {
127 case -2: return -1;
128 case -1: return def_action;
129 default: return ret;
130 }
131 }
132 #endif
133
134 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
135 enum lxc_hostarch_t {
136 lxc_seccomp_arch_all = 0,
137 lxc_seccomp_arch_native,
138 lxc_seccomp_arch_i386,
139 lxc_seccomp_arch_x32,
140 lxc_seccomp_arch_amd64,
141 lxc_seccomp_arch_arm,
142 lxc_seccomp_arch_arm64,
143 lxc_seccomp_arch_ppc64,
144 lxc_seccomp_arch_ppc64le,
145 lxc_seccomp_arch_ppc,
146 lxc_seccomp_arch_mips,
147 lxc_seccomp_arch_mips64,
148 lxc_seccomp_arch_mips64n32,
149 lxc_seccomp_arch_mipsel,
150 lxc_seccomp_arch_mipsel64,
151 lxc_seccomp_arch_mipsel64n32,
152 lxc_seccomp_arch_s390x,
153 lxc_seccomp_arch_unknown = 999,
154 };
155
156 #ifdef __MIPSEL__
157 # define MIPS_ARCH_O32 lxc_seccomp_arch_mipsel
158 # define MIPS_ARCH_N64 lxc_seccomp_arch_mipsel64
159 #else
160 # define MIPS_ARCH_O32 lxc_seccomp_arch_mips
161 # define MIPS_ARCH_N64 lxc_seccomp_arch_mips64
162 #endif
163
164 int get_hostarch(void)
165 {
166 struct utsname uts;
167 if (uname(&uts) < 0) {
168 SYSERROR("Failed to read host arch.");
169 return -1;
170 }
171 if (strcmp(uts.machine, "i686") == 0)
172 return lxc_seccomp_arch_i386;
173 // no x32 kernels
174 else if (strcmp(uts.machine, "x86_64") == 0)
175 return lxc_seccomp_arch_amd64;
176 else if (strncmp(uts.machine, "armv7", 5) == 0)
177 return lxc_seccomp_arch_arm;
178 else if (strncmp(uts.machine, "aarch64", 7) == 0)
179 return lxc_seccomp_arch_arm64;
180 else if (strncmp(uts.machine, "ppc64le", 7) == 0)
181 return lxc_seccomp_arch_ppc64le;
182 else if (strncmp(uts.machine, "ppc64", 5) == 0)
183 return lxc_seccomp_arch_ppc64;
184 else if (strncmp(uts.machine, "ppc", 3) == 0)
185 return lxc_seccomp_arch_ppc;
186 else if (strncmp(uts.machine, "mips64", 6) == 0)
187 return MIPS_ARCH_N64;
188 else if (strncmp(uts.machine, "mips", 4) == 0)
189 return MIPS_ARCH_O32;
190 else if (strncmp(uts.machine, "s390x", 5) == 0)
191 return lxc_seccomp_arch_s390x;
192 return lxc_seccomp_arch_unknown;
193 }
194
195 scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action)
196 {
197 scmp_filter_ctx ctx;
198 int ret;
199 uint32_t arch;
200
201 switch(n_arch) {
202 case lxc_seccomp_arch_i386: arch = SCMP_ARCH_X86; break;
203 case lxc_seccomp_arch_x32: arch = SCMP_ARCH_X32; break;
204 case lxc_seccomp_arch_amd64: arch = SCMP_ARCH_X86_64; break;
205 case lxc_seccomp_arch_arm: arch = SCMP_ARCH_ARM; break;
206 #ifdef SCMP_ARCH_AARCH64
207 case lxc_seccomp_arch_arm64: arch = SCMP_ARCH_AARCH64; break;
208 #endif
209 #ifdef SCMP_ARCH_PPC64LE
210 case lxc_seccomp_arch_ppc64le: arch = SCMP_ARCH_PPC64LE; break;
211 #endif
212 #ifdef SCMP_ARCH_PPC64
213 case lxc_seccomp_arch_ppc64: arch = SCMP_ARCH_PPC64; break;
214 #endif
215 #ifdef SCMP_ARCH_PPC
216 case lxc_seccomp_arch_ppc: arch = SCMP_ARCH_PPC; break;
217 #endif
218 #ifdef SCMP_ARCH_MIPS
219 case lxc_seccomp_arch_mips: arch = SCMP_ARCH_MIPS; break;
220 case lxc_seccomp_arch_mips64: arch = SCMP_ARCH_MIPS64; break;
221 case lxc_seccomp_arch_mips64n32: arch = SCMP_ARCH_MIPS64N32; break;
222 case lxc_seccomp_arch_mipsel: arch = SCMP_ARCH_MIPSEL; break;
223 case lxc_seccomp_arch_mipsel64: arch = SCMP_ARCH_MIPSEL64; break;
224 case lxc_seccomp_arch_mipsel64n32: arch = SCMP_ARCH_MIPSEL64N32; break;
225 #endif
226 #ifdef SCMP_ARCH_S390X
227 case lxc_seccomp_arch_s390x: arch = SCMP_ARCH_S390X; break;
228 #endif
229 default: return NULL;
230 }
231
232 if ((ctx = seccomp_init(default_policy_action)) == NULL) {
233 ERROR("Error initializing seccomp context.");
234 return NULL;
235 }
236 if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)) {
237 ERROR("Failed to turn off no-new-privs.");
238 seccomp_release(ctx);
239 return NULL;
240 }
241 #ifdef SCMP_FLTATR_ATL_TSKIP
242 if (seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
243 WARN("Failed to turn on seccomp nop-skip, continuing");
244 }
245 #endif
246 ret = seccomp_arch_add(ctx, arch);
247 if (ret != 0) {
248 ERROR("Seccomp error %d (%s) adding arch: %d", ret,
249 strerror(-ret), (int)n_arch);
250 seccomp_release(ctx);
251 return NULL;
252 }
253 if (seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE) != 0) {
254 ERROR("Seccomp error removing native arch");
255 seccomp_release(ctx);
256 return NULL;
257 }
258
259 return ctx;
260 }
261
262 bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
263 uint32_t action)
264 {
265 int nr, ret;
266
267 ret = seccomp_arch_exist(ctx, arch);
268 if (arch && ret != 0) {
269 ERROR("BUG: Seccomp: rule and context arch do not match (arch "
270 "%d): %s.",
271 arch, strerror(-ret));
272 return false;
273 }
274
275 if (strncmp(line, "reject_force_umount", 19) == 0) {
276 INFO("Setting Seccomp rule to reject force umounts.");
277 ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(umount2),
278 1, SCMP_A1(SCMP_CMP_MASKED_EQ , MNT_FORCE , MNT_FORCE ));
279 if (ret < 0) {
280 ERROR("Failed (%d) loading rule to reject force "
281 "umount: %s.",
282 ret, strerror(-ret));
283 return false;
284 }
285 return true;
286 }
287
288 nr = seccomp_syscall_resolve_name(line);
289 if (nr == __NR_SCMP_ERROR) {
290 WARN("Seccomp: failed to resolve syscall: %s.", line);
291 WARN("This syscall will NOT be blacklisted.");
292 return true;
293 }
294 if (nr < 0) {
295 WARN("Seccomp: got negative for syscall: %d: %s.", nr, line);
296 WARN("This syscall will NOT be blacklisted.");
297 return true;
298 }
299 ret = seccomp_rule_add_exact(ctx, action, nr, 0);
300 if (ret < 0) {
301 ERROR("Failed (%d) loading rule for %s (nr %d action %d(%s)): %s.",
302 ret, line, nr, action, get_action_name(action), strerror(-ret));
303 return false;
304 }
305 return true;
306 }
307
308 /*
309 * v2 consists of
310 * [x86]
311 * open
312 * read
313 * write
314 * close
315 * # a comment
316 * [x86_64]
317 * open
318 * read
319 * write
320 * close
321 */
322 static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
323 {
324 char *p;
325 int ret;
326 scmp_filter_ctx compat_ctx[2] = {NULL, NULL};
327 bool blacklist = false;
328 uint32_t default_policy_action = -1, default_rule_action = -1, action;
329 enum lxc_hostarch_t native_arch = get_hostarch(),
330 cur_rule_arch = native_arch;
331 uint32_t compat_arch[2] = {SCMP_ARCH_NATIVE, SCMP_ARCH_NATIVE};
332
333 if (strncmp(line, "blacklist", 9) == 0)
334 blacklist = true;
335 else if (strncmp(line, "whitelist", 9) != 0) {
336 ERROR("Bad seccomp policy style: %s.", line);
337 return -1;
338 }
339
340 if ((p = strchr(line, ' '))) {
341 default_policy_action = get_v2_default_action(p + 1);
342 if (default_policy_action == -2)
343 return -1;
344 }
345
346 /* for blacklist, allow any syscall which has no rule */
347 if (blacklist) {
348 if (default_policy_action == -1)
349 default_policy_action = SCMP_ACT_ALLOW;
350 if (default_rule_action == -1)
351 default_rule_action = SCMP_ACT_KILL;
352 } else {
353 if (default_policy_action == -1)
354 default_policy_action = SCMP_ACT_KILL;
355 if (default_rule_action == -1)
356 default_rule_action = SCMP_ACT_ALLOW;
357 }
358
359 if (native_arch == lxc_seccomp_arch_amd64) {
360 cur_rule_arch = lxc_seccomp_arch_all;
361 compat_arch[0] = SCMP_ARCH_X86;
362 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_i386,
363 default_policy_action);
364 compat_arch[1] = SCMP_ARCH_X32;
365 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_x32,
366 default_policy_action);
367 if (!compat_ctx[0] || !compat_ctx[1])
368 goto bad;
369 #ifdef SCMP_ARCH_PPC
370 } else if (native_arch == lxc_seccomp_arch_ppc64) {
371 cur_rule_arch = lxc_seccomp_arch_all;
372 compat_arch[0] = SCMP_ARCH_PPC;
373 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_ppc,
374 default_policy_action);
375 if (!compat_ctx[0])
376 goto bad;
377 #endif
378 #ifdef SCMP_ARCH_ARM
379 } else if (native_arch == lxc_seccomp_arch_arm64) {
380 cur_rule_arch = lxc_seccomp_arch_all;
381 compat_arch[0] = SCMP_ARCH_ARM;
382 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_arm,
383 default_policy_action);
384 if (!compat_ctx[0])
385 goto bad;
386 #endif
387 #ifdef SCMP_ARCH_MIPS
388 } else if (native_arch == lxc_seccomp_arch_mips64) {
389 cur_rule_arch = lxc_seccomp_arch_all;
390 compat_arch[0] = SCMP_ARCH_MIPS;
391 compat_arch[1] = SCMP_ARCH_MIPS64N32;
392 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mips,
393 default_policy_action);
394 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mips64n32,
395 default_policy_action);
396 if (!compat_ctx[0] || !compat_ctx[1])
397 goto bad;
398 } else if (native_arch == lxc_seccomp_arch_mipsel64) {
399 cur_rule_arch = lxc_seccomp_arch_all;
400 compat_arch[0] = SCMP_ARCH_MIPSEL;
401 compat_arch[1] = SCMP_ARCH_MIPSEL64N32;
402 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mipsel,
403 default_policy_action);
404 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32,
405 default_policy_action);
406 if (!compat_ctx[0] || !compat_ctx[1])
407 goto bad;
408 #endif
409 }
410
411 if (default_policy_action != SCMP_ACT_KILL) {
412 ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
413 if (ret != 0) {
414 ERROR("Error re-initializing Seccomp.");
415 return -1;
416 }
417 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) {
418 ERROR("Failed to turn off no-new-privs.");
419 return -1;
420 }
421 #ifdef SCMP_FLTATR_ATL_TSKIP
422 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
423 WARN("Failed to turn on seccomp nop-skip, continuing");
424 }
425 #endif
426 }
427
428 while (fgets(line, 1024, f)) {
429
430 if (line[0] == '#')
431 continue;
432 if (strlen(line) == 0)
433 continue;
434 remove_trailing_newlines(line);
435 INFO("processing: .%s.", line);
436 if (line[0] == '[') {
437 // read the architecture for next set of rules
438 if (strcmp(line, "[x86]") == 0 ||
439 strcmp(line, "[X86]") == 0) {
440 if (native_arch != lxc_seccomp_arch_i386 &&
441 native_arch != lxc_seccomp_arch_amd64) {
442 cur_rule_arch = lxc_seccomp_arch_unknown;
443 continue;
444 }
445 cur_rule_arch = lxc_seccomp_arch_i386;
446 } else if (strcmp(line, "[x32]") == 0 ||
447 strcmp(line, "[X32]") == 0) {
448 if (native_arch != lxc_seccomp_arch_amd64) {
449 cur_rule_arch = lxc_seccomp_arch_unknown;
450 continue;
451 }
452 cur_rule_arch = lxc_seccomp_arch_x32;
453 } else if (strcmp(line, "[X86_64]") == 0 ||
454 strcmp(line, "[x86_64]") == 0) {
455 if (native_arch != lxc_seccomp_arch_amd64) {
456 cur_rule_arch = lxc_seccomp_arch_unknown;
457 continue;
458 }
459 cur_rule_arch = lxc_seccomp_arch_amd64;
460 } else if (strcmp(line, "[all]") == 0 ||
461 strcmp(line, "[ALL]") == 0) {
462 cur_rule_arch = lxc_seccomp_arch_all;
463 }
464 #ifdef SCMP_ARCH_ARM
465 else if (strcmp(line, "[arm]") == 0 ||
466 strcmp(line, "[ARM]") == 0) {
467 if (native_arch != lxc_seccomp_arch_arm &&
468 native_arch != lxc_seccomp_arch_arm64) {
469 cur_rule_arch = lxc_seccomp_arch_unknown;
470 continue;
471 }
472 cur_rule_arch = lxc_seccomp_arch_arm;
473 }
474 #endif
475 #ifdef SCMP_ARCH_AARCH64
476 else if (strcmp(line, "[arm64]") == 0 ||
477 strcmp(line, "[ARM64]") == 0) {
478 if (native_arch != lxc_seccomp_arch_arm64) {
479 cur_rule_arch = lxc_seccomp_arch_unknown;
480 continue;
481 }
482 cur_rule_arch = lxc_seccomp_arch_arm64;
483 }
484 #endif
485 #ifdef SCMP_ARCH_PPC64LE
486 else if (strcmp(line, "[ppc64le]") == 0 ||
487 strcmp(line, "[PPC64LE]") == 0) {
488 if (native_arch != lxc_seccomp_arch_ppc64le) {
489 cur_rule_arch = lxc_seccomp_arch_unknown;
490 continue;
491 }
492 cur_rule_arch = lxc_seccomp_arch_ppc64le;
493 }
494 #endif
495 #ifdef SCMP_ARCH_PPC64
496 else if (strcmp(line, "[ppc64]") == 0 ||
497 strcmp(line, "[PPC64]") == 0) {
498 if (native_arch != lxc_seccomp_arch_ppc64) {
499 cur_rule_arch = lxc_seccomp_arch_unknown;
500 continue;
501 }
502 cur_rule_arch = lxc_seccomp_arch_ppc64;
503 }
504 #endif
505 #ifdef SCMP_ARCH_PPC
506 else if (strcmp(line, "[ppc]") == 0 ||
507 strcmp(line, "[PPC]") == 0) {
508 if (native_arch != lxc_seccomp_arch_ppc &&
509 native_arch != lxc_seccomp_arch_ppc64) {
510 cur_rule_arch = lxc_seccomp_arch_unknown;
511 continue;
512 }
513 cur_rule_arch = lxc_seccomp_arch_ppc;
514 }
515 #endif
516 #ifdef SCMP_ARCH_MIPS
517 else if (strcmp(line, "[mips64]") == 0 ||
518 strcmp(line, "[MIPS64]") == 0) {
519 if (native_arch != lxc_seccomp_arch_mips64) {
520 cur_rule_arch = lxc_seccomp_arch_unknown;
521 continue;
522 }
523 cur_rule_arch = lxc_seccomp_arch_mips64;
524 } else if (strcmp(line, "[mips64n32]") == 0 ||
525 strcmp(line, "[MIPS64N32]") == 0) {
526 if (native_arch != lxc_seccomp_arch_mips64) {
527 cur_rule_arch = lxc_seccomp_arch_unknown;
528 continue;
529 }
530 cur_rule_arch = lxc_seccomp_arch_mips64n32;
531 } else if (strcmp(line, "[mips]") == 0 ||
532 strcmp(line, "[MIPS]") == 0) {
533 if (native_arch != lxc_seccomp_arch_mips &&
534 native_arch != lxc_seccomp_arch_mips64) {
535 cur_rule_arch = lxc_seccomp_arch_unknown;
536 continue;
537 }
538 cur_rule_arch = lxc_seccomp_arch_mips;
539 } else if (strcmp(line, "[mipsel64]") == 0 ||
540 strcmp(line, "[MIPSEL64]") == 0) {
541 if (native_arch != lxc_seccomp_arch_mipsel64) {
542 cur_rule_arch = lxc_seccomp_arch_unknown;
543 continue;
544 }
545 cur_rule_arch = lxc_seccomp_arch_mipsel64;
546 } else if (strcmp(line, "[mipsel64n32]") == 0 ||
547 strcmp(line, "[MIPSEL64N32]") == 0) {
548 if (native_arch != lxc_seccomp_arch_mipsel64) {
549 cur_rule_arch = lxc_seccomp_arch_unknown;
550 continue;
551 }
552 cur_rule_arch = lxc_seccomp_arch_mipsel64n32;
553 } else if (strcmp(line, "[mipsel]") == 0 ||
554 strcmp(line, "[MIPSEL]") == 0) {
555 if (native_arch != lxc_seccomp_arch_mipsel &&
556 native_arch != lxc_seccomp_arch_mipsel64) {
557 cur_rule_arch = lxc_seccomp_arch_unknown;
558 continue;
559 }
560 cur_rule_arch = lxc_seccomp_arch_mipsel;
561 }
562 #endif
563 #ifdef SCMP_ARCH_S390X
564 else if (strcmp(line, "[s390x]") == 0 ||
565 strcmp(line, "[S390X]") == 0) {
566 if (native_arch != lxc_seccomp_arch_s390x) {
567 cur_rule_arch = lxc_seccomp_arch_unknown;
568 continue;
569 }
570 cur_rule_arch = lxc_seccomp_arch_s390x;
571 }
572 #endif
573 else
574 goto bad_arch;
575
576 continue;
577 }
578
579 /* irrelevant arch - i.e. arm on i386 */
580 if (cur_rule_arch == lxc_seccomp_arch_unknown)
581 continue;
582
583 /* read optional action which follows the syscall */
584 action = get_and_clear_v2_action(line, default_rule_action);
585 if (action == -1) {
586 ERROR("Failed to interpret action.");
587 goto bad_rule;
588 }
589
590 if (cur_rule_arch == native_arch ||
591 cur_rule_arch == lxc_seccomp_arch_native ||
592 compat_arch[0] == SCMP_ARCH_NATIVE) {
593 INFO("Adding native rule for %s action %d(%s).", line, action,
594 get_action_name(action));
595 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
596 goto bad_rule;
597 }
598 else if (cur_rule_arch != lxc_seccomp_arch_all) {
599 int arch_index =
600 cur_rule_arch == lxc_seccomp_arch_mips64n32 ||
601 cur_rule_arch == lxc_seccomp_arch_mipsel64n32 ? 1 : 0;
602
603 INFO("Adding compat-only rule for %s action %d(%s).", line, action,
604 get_action_name(action));
605 if (!do_resolve_add_rule(compat_arch[arch_index], line, compat_ctx[arch_index], action))
606 goto bad_rule;
607 }
608 else {
609 INFO("Adding native rule for %s action %d(%s).", line, action,
610 get_action_name(action));
611 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
612 goto bad_rule;
613 INFO("Adding compat rule for %s action %d(%s).", line, action,
614 get_action_name(action));
615 if (!do_resolve_add_rule(compat_arch[0], line, compat_ctx[0], action))
616 goto bad_rule;
617 if (compat_arch[1] != SCMP_ARCH_NATIVE &&
618 !do_resolve_add_rule(compat_arch[1], line, compat_ctx[1], action))
619 goto bad_rule;
620 }
621 }
622
623 if (compat_ctx[0]) {
624 INFO("Merging in the compat Seccomp ctx into the main one.");
625 if (seccomp_merge(conf->seccomp_ctx, compat_ctx[0]) != 0 ||
626 (compat_ctx[1] != NULL && seccomp_merge(conf->seccomp_ctx, compat_ctx[1]) != 0)) {
627 ERROR("Error merging compat Seccomp contexts.");
628 goto bad;
629 }
630 }
631
632 return 0;
633
634 bad_arch:
635 ERROR("Unsupported arch: %s.", line);
636 bad_rule:
637 bad:
638 if (compat_ctx[0])
639 seccomp_release(compat_ctx[0]);
640 if (compat_ctx[1])
641 seccomp_release(compat_ctx[1]);
642 return -1;
643 }
644 #else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
645 static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
646 {
647 return -1;
648 }
649 #endif /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
650
651 /*
652 * The first line of the config file has a policy language version
653 * the second line has some directives
654 * then comes policy subject to the directives
655 * right now version must be '1' or '2'
656 * the directives must include 'whitelist'(version == 1 or 2) or 'blacklist'
657 * (version == 2) and can include 'debug' (though debug is not yet supported).
658 */
659 static int parse_config(FILE *f, struct lxc_conf *conf)
660 {
661 char line[1024];
662 int ret, version;
663
664 ret = fscanf(f, "%d\n", &version);
665 if (ret != 1 || (version != 1 && version != 2)) {
666 ERROR("Invalid version.");
667 return -1;
668 }
669 if (!fgets(line, 1024, f)) {
670 ERROR("Invalid config file.");
671 return -1;
672 }
673 if (version == 1 && !strstr(line, "whitelist")) {
674 ERROR("Only whitelist policy is supported.");
675 return -1;
676 }
677
678 if (strstr(line, "debug")) {
679 ERROR("Debug not yet implemented.");
680 return -1;
681 }
682
683 if (version == 1)
684 return parse_config_v1(f, conf);
685 return parse_config_v2(f, line, conf);
686 }
687
688 /*
689 * use_seccomp: return true if we should try and apply a seccomp policy
690 * if defined for the container.
691 * This will return false if
692 * 1. seccomp is not enabled in the kernel
693 * 2. a seccomp policy is already enabled for this task
694 */
695 static bool use_seccomp(void)
696 {
697 FILE *f = fopen("/proc/self/status", "r");
698 char line[1024];
699 bool already_enabled = false;
700 bool found = false;
701 int ret, v;
702
703 if (!f)
704 return true;
705
706 while (fgets(line, 1024, f)) {
707 if (strncmp(line, "Seccomp:", 8) == 0) {
708 found = true;
709 ret = sscanf(line + 8, "%d", &v);
710 if (ret == 1 && v != 0)
711 already_enabled = true;
712 break;
713 }
714 }
715
716 fclose(f);
717 if (!found) { /* no Seccomp line, no seccomp in kernel */
718 INFO("Seccomp is not enabled in the kernel.");
719 return false;
720 }
721 if (already_enabled) { /* already seccomp-confined */
722 INFO("Already seccomp-confined, not loading new policy.");
723 return false;
724 }
725 return true;
726 }
727
728 int lxc_read_seccomp_config(struct lxc_conf *conf)
729 {
730 FILE *f;
731 int ret;
732 int check_seccomp_attr_set;
733
734 if (!conf->seccomp)
735 return 0;
736
737 if (!use_seccomp())
738 return 0;
739 #if HAVE_SCMP_FILTER_CTX
740 /* XXX for debug, pass in SCMP_ACT_TRAP */
741 conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL);
742 ret = !conf->seccomp_ctx;
743 #else
744 ret = seccomp_init(SCMP_ACT_KILL) < 0;
745 #endif
746 if (ret) {
747 ERROR("Failed initializing seccomp.");
748 return -1;
749 }
750
751 /* turn off no-new-privs. We don't want it in lxc, and it breaks
752 * with apparmor */
753 #if HAVE_SCMP_FILTER_CTX
754 check_seccomp_attr_set = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
755 #else
756 check_seccomp_attr_set = seccomp_attr_set(SCMP_FLTATR_CTL_NNP, 0);
757 #endif
758 if (check_seccomp_attr_set) {
759 ERROR("Failed to turn off no-new-privs.");
760 return -1;
761 }
762 #ifdef SCMP_FLTATR_ATL_TSKIP
763 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
764 WARN("Failed to turn on seccomp nop-skip, continuing");
765 }
766 #endif
767
768 f = fopen(conf->seccomp, "r");
769 if (!f) {
770 SYSERROR("Failed to open seccomp policy file %s.", conf->seccomp);
771 return -1;
772 }
773 ret = parse_config(f, conf);
774 fclose(f);
775 return ret;
776 }
777
778 int lxc_seccomp_load(struct lxc_conf *conf)
779 {
780 int ret;
781 if (!conf->seccomp)
782 return 0;
783 if (!use_seccomp())
784 return 0;
785 ret = seccomp_load(
786 #if HAVE_SCMP_FILTER_CTX
787 conf->seccomp_ctx
788 #endif
789 );
790 if (ret < 0) {
791 ERROR("Error loading the seccomp policy: %s.", strerror(-ret));
792 return -1;
793 }
794
795 /* After load seccomp filter into the kernel successfully, export the current seccomp
796 * filter to log file */
797 #if HAVE_SCMP_FILTER_CTX
798 if ((lxc_log_get_level() <= LXC_LOG_LEVEL_TRACE || conf->loglevel <= LXC_LOG_LEVEL_TRACE) &&
799 lxc_log_fd >= 0) {
800 ret = seccomp_export_pfc(conf->seccomp_ctx, lxc_log_fd);
801 /* Just give an warning when export error */
802 if (ret < 0)
803 WARN("Failed to export seccomp filter to log file: %s.", strerror(-ret));
804 }
805 #endif
806 return 0;
807 }
808
809 void lxc_seccomp_free(struct lxc_conf *conf)
810 {
811 free(conf->seccomp);
812 conf->seccomp = NULL;
813 #if HAVE_SCMP_FILTER_CTX
814 if (conf->seccomp_ctx) {
815 seccomp_release(conf->seccomp_ctx);
816 conf->seccomp_ctx = NULL;
817 }
818 #endif
819 }