]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/seccomp.c
seccomp: cleanup compat architecture handling
[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_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++;
120 while (*p == ' ')
121 p++;
122 if (!*p || *p == '#')
123 return def_action;
124 ret = get_v2_default_action(p);
125 switch(ret) {
126 case -2: return -1;
127 case -1: return def_action;
128 default: return ret;
129 }
130 }
131
132 struct v2_rule_args {
133 uint32_t index;
134 uint64_t value;
135 uint64_t mask;
136 enum scmp_compare op;
137 };
138
139 struct seccomp_v2_rule {
140 uint32_t action;
141 uint32_t args_num;
142 struct v2_rule_args args_value[6];
143 };
144
145 static enum scmp_compare parse_v2_rule_op(char *s)
146 {
147 if (strcmp(s, "SCMP_CMP_NE") == 0 || strcmp(s, "!=") == 0)
148 return SCMP_CMP_NE;
149 else if (strcmp(s, "SCMP_CMP_LT") == 0 || strcmp(s, "<") == 0)
150 return SCMP_CMP_LT;
151 else if (strcmp(s, "SCMP_CMP_LE") == 0 || strcmp(s, "<=") == 0)
152 return SCMP_CMP_LE;
153 else if (strcmp(s, "SCMP_CMP_EQ") == 0 || strcmp(s, "==") == 0)
154 return SCMP_CMP_EQ;
155 else if (strcmp(s, "SCMP_CMP_GE") == 0 || strcmp(s, ">=") == 0)
156 return SCMP_CMP_GE;
157 else if (strcmp(s, "SCMP_CMP_GT") == 0 || strcmp(s, ">") == 0)
158 return SCMP_CMP_GT;
159 else if (strcmp(s, "SCMP_CMP_MASKED_EQ") == 0 || strcmp(s, "&=") == 0)
160 return SCMP_CMP_MASKED_EQ;
161
162 return _SCMP_CMP_MAX;
163 }
164
165 /* This function is used to parse the args string into the structure.
166 * args string format:[index,value,op,valueTwo] or [index,value,op]
167 * For one arguments, [index,value,valueTwo,op]
168 * index: the index for syscall arguments (type uint)
169 * value: the value for syscall arguments (type uint64)
170 * op: the operator for syscall arguments(string),
171 a valid list of constants as of libseccomp v2.3.2 is
172 SCMP_CMP_NE,SCMP_CMP_LE,SCMP_CMP_LE, SCMP_CMP_EQ, SCMP_CMP_GE,
173 SCMP_CMP_GT, SCMP_CMP_MASKED_EQ, or !=,<=,==,>=,>,&=
174 * valueTwo: the value for syscall arguments only used for mask eq (type uint64, optional)
175 * Returns 0 on success, < 0 otherwise.
176 */
177 static int get_seccomp_arg_value(char *key, struct v2_rule_args *rule_args)
178 {
179 int ret = 0;
180 uint64_t value = 0;
181 uint64_t mask = 0;
182 enum scmp_compare op = 0;
183 uint32_t index = 0;
184 char s[30] = {0};
185 char *tmp = NULL;
186
187 memset(s, 0, sizeof(s));
188 tmp = strchr(key, '[');
189 if (!tmp) {
190 ERROR("Failed to interpret args");
191 return -1;
192 }
193 ret = sscanf(tmp, "[%i,%lli,%30[^0-9^,],%lli", &index, (long long unsigned int *)&value, s, (long long unsigned int *)&mask);
194 if ((ret != 3 && ret != 4) || index >= 6) {
195 ERROR("Failed to interpret args value");
196 return -1;
197 }
198
199 op = parse_v2_rule_op(s);
200 if (op == _SCMP_CMP_MAX) {
201 ERROR("Failed to interpret args operator value");
202 return -1;
203 }
204
205 rule_args->index = index;
206 rule_args->value = value;
207 rule_args->mask = mask;
208 rule_args->op = op;
209 return 0;
210 }
211
212 /* This function is used to parse the seccomp rule entry.
213 * @line : seccomp rule entry string.
214 * @def_action : default action used in the case if the 'line' contain non valid action.
215 * @rules : output struct.
216 * Returns 0 on success, < 0 otherwise.
217 */
218 static int parse_v2_rules(char *line, uint32_t def_action, struct seccomp_v2_rule *rules)
219 {
220 int ret = 0 ;
221 int i = 0;
222 char *tmp = NULL;
223 char *key = NULL;
224 char *saveptr = NULL;
225
226 tmp = strdup(line);
227 if (!tmp)
228 return -1;
229
230 /* read optional action which follows the syscall */
231 rules->action = get_v2_action(tmp, def_action);
232 if (rules->action == -1) {
233 ERROR("Failed to interpret action");
234 ret = -1;
235 goto out;
236 }
237
238 rules->args_num = 0;
239 if (!strchr(tmp, '[')) {
240 ret = 0;
241 goto out;
242 }
243
244 for ((key = strtok_r(tmp, "]", &saveptr)), i = 0; key && i < 6; (key = strtok_r(NULL, "]", &saveptr)), i++) {
245 ret = get_seccomp_arg_value(key, &rules->args_value[i]);
246 if (ret < 0) {
247 ret = -1;
248 goto out;
249 }
250 rules->args_num++;
251 }
252
253 ret = 0;
254 out:
255 free(tmp);
256 return ret;
257 }
258
259 #endif
260
261 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
262 enum lxc_hostarch_t {
263 lxc_seccomp_arch_all = 0,
264 lxc_seccomp_arch_native,
265 lxc_seccomp_arch_i386,
266 lxc_seccomp_arch_x32,
267 lxc_seccomp_arch_amd64,
268 lxc_seccomp_arch_arm,
269 lxc_seccomp_arch_arm64,
270 lxc_seccomp_arch_ppc64,
271 lxc_seccomp_arch_ppc64le,
272 lxc_seccomp_arch_ppc,
273 lxc_seccomp_arch_mips,
274 lxc_seccomp_arch_mips64,
275 lxc_seccomp_arch_mips64n32,
276 lxc_seccomp_arch_mipsel,
277 lxc_seccomp_arch_mipsel64,
278 lxc_seccomp_arch_mipsel64n32,
279 lxc_seccomp_arch_s390x,
280 lxc_seccomp_arch_unknown = 999,
281 };
282
283 #ifdef __MIPSEL__
284 # define MIPS_ARCH_O32 lxc_seccomp_arch_mipsel
285 # define MIPS_ARCH_N64 lxc_seccomp_arch_mipsel64
286 #else
287 # define MIPS_ARCH_O32 lxc_seccomp_arch_mips
288 # define MIPS_ARCH_N64 lxc_seccomp_arch_mips64
289 #endif
290
291 int get_hostarch(void)
292 {
293 struct utsname uts;
294 if (uname(&uts) < 0) {
295 SYSERROR("Failed to read host arch");
296 return -1;
297 }
298 if (strcmp(uts.machine, "i686") == 0)
299 return lxc_seccomp_arch_i386;
300 /* no x32 kernels */
301 else if (strcmp(uts.machine, "x86_64") == 0)
302 return lxc_seccomp_arch_amd64;
303 else if (strncmp(uts.machine, "armv7", 5) == 0)
304 return lxc_seccomp_arch_arm;
305 else if (strncmp(uts.machine, "aarch64", 7) == 0)
306 return lxc_seccomp_arch_arm64;
307 else if (strncmp(uts.machine, "ppc64le", 7) == 0)
308 return lxc_seccomp_arch_ppc64le;
309 else if (strncmp(uts.machine, "ppc64", 5) == 0)
310 return lxc_seccomp_arch_ppc64;
311 else if (strncmp(uts.machine, "ppc", 3) == 0)
312 return lxc_seccomp_arch_ppc;
313 else if (strncmp(uts.machine, "mips64", 6) == 0)
314 return MIPS_ARCH_N64;
315 else if (strncmp(uts.machine, "mips", 4) == 0)
316 return MIPS_ARCH_O32;
317 else if (strncmp(uts.machine, "s390x", 5) == 0)
318 return lxc_seccomp_arch_s390x;
319 return lxc_seccomp_arch_unknown;
320 }
321
322 scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action)
323 {
324 scmp_filter_ctx ctx;
325 int ret;
326 uint32_t arch;
327
328 switch(n_arch) {
329 case lxc_seccomp_arch_i386: arch = SCMP_ARCH_X86; break;
330 case lxc_seccomp_arch_x32: arch = SCMP_ARCH_X32; break;
331 case lxc_seccomp_arch_amd64: arch = SCMP_ARCH_X86_64; break;
332 case lxc_seccomp_arch_arm: arch = SCMP_ARCH_ARM; break;
333 #ifdef SCMP_ARCH_AARCH64
334 case lxc_seccomp_arch_arm64: arch = SCMP_ARCH_AARCH64; break;
335 #endif
336 #ifdef SCMP_ARCH_PPC64LE
337 case lxc_seccomp_arch_ppc64le: arch = SCMP_ARCH_PPC64LE; break;
338 #endif
339 #ifdef SCMP_ARCH_PPC64
340 case lxc_seccomp_arch_ppc64: arch = SCMP_ARCH_PPC64; break;
341 #endif
342 #ifdef SCMP_ARCH_PPC
343 case lxc_seccomp_arch_ppc: arch = SCMP_ARCH_PPC; break;
344 #endif
345 #ifdef SCMP_ARCH_MIPS
346 case lxc_seccomp_arch_mips: arch = SCMP_ARCH_MIPS; break;
347 case lxc_seccomp_arch_mips64: arch = SCMP_ARCH_MIPS64; break;
348 case lxc_seccomp_arch_mips64n32: arch = SCMP_ARCH_MIPS64N32; break;
349 case lxc_seccomp_arch_mipsel: arch = SCMP_ARCH_MIPSEL; break;
350 case lxc_seccomp_arch_mipsel64: arch = SCMP_ARCH_MIPSEL64; break;
351 case lxc_seccomp_arch_mipsel64n32: arch = SCMP_ARCH_MIPSEL64N32; break;
352 #endif
353 #ifdef SCMP_ARCH_S390X
354 case lxc_seccomp_arch_s390x: arch = SCMP_ARCH_S390X; break;
355 #endif
356 default: return NULL;
357 }
358
359 if ((ctx = seccomp_init(default_policy_action)) == NULL) {
360 ERROR("Error initializing seccomp context");
361 return NULL;
362 }
363 if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)) {
364 ERROR("Failed to turn off no-new-privs");
365 seccomp_release(ctx);
366 return NULL;
367 }
368 #ifdef SCMP_FLTATR_ATL_TSKIP
369 if (seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
370 WARN("Failed to turn on seccomp nop-skip, continuing");
371 }
372 #endif
373
374 ret = seccomp_arch_exist(ctx, arch);
375 if (ret < 0) {
376 if (ret != -EEXIST) {
377 ERROR("%s - Failed to determine whether arch %d is "
378 "already present in the main seccomp context",
379 strerror(-ret), (int)n_arch);
380 seccomp_release(ctx);
381 return NULL;
382 }
383
384 ret = seccomp_arch_add(ctx, arch);
385 if (ret != 0) {
386 ERROR("%s - Failed to add arch %d to main seccomp context",
387 strerror(-ret), (int)n_arch);
388 seccomp_release(ctx);
389 return NULL;
390 }
391 TRACE("Added arch %d to main seccomp context", (int)n_arch);
392
393 ret = seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE);
394 if (ret != 0) {
395 ERROR("Failed to remove native arch from main seccomp context");
396 seccomp_release(ctx);
397 return NULL;
398 }
399 TRACE("Removed native arch from main seccomp context");
400 } else {
401 TRACE("Arch %d already present in main seccomp context", (int)n_arch);
402 }
403
404 return ctx;
405 }
406
407 bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
408 struct seccomp_v2_rule *rule)
409 {
410 int nr, ret, i;
411 struct scmp_arg_cmp arg_cmp[6];
412
413 memset(arg_cmp, 0 ,sizeof(arg_cmp));
414
415 ret = seccomp_arch_exist(ctx, arch);
416 if (arch && ret != 0) {
417 ERROR("BUG: Seccomp: rule and context arch do not match (arch "
418 "%d): %s",
419 arch, strerror(-ret));
420 return false;
421 }
422
423 /*get the syscall name*/
424 char *p = strchr(line, ' ');
425 if (p)
426 *p = '\0';
427
428 if (strncmp(line, "reject_force_umount", 19) == 0) {
429 INFO("Setting Seccomp rule to reject force umounts");
430 ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(umount2),
431 1, SCMP_A1(SCMP_CMP_MASKED_EQ , MNT_FORCE , MNT_FORCE ));
432 if (ret < 0) {
433 ERROR("Failed (%d) loading rule to reject force "
434 "umount: %s",
435 ret, strerror(-ret));
436 return false;
437 }
438 return true;
439 }
440
441 nr = seccomp_syscall_resolve_name(line);
442 if (nr == __NR_SCMP_ERROR) {
443 WARN("Seccomp: failed to resolve syscall: %s", line);
444 WARN("This syscall will NOT be blacklisted");
445 return true;
446 }
447 if (nr < 0) {
448 WARN("Seccomp: got negative for syscall: %d: %s", nr, line);
449 WARN("This syscall will NOT be blacklisted");
450 return true;
451 }
452
453 for (i = 0; i < rule->args_num; i++) {
454 INFO("arg_cmp[%d]:SCMP_CMP(%u, %llu, %llu, %llu)", i,
455 rule->args_value[i].index,
456 (long long unsigned int)rule->args_value[i].op,
457 (long long unsigned int)rule->args_value[i].mask,
458 (long long unsigned int)rule->args_value[i].value);
459
460 if (SCMP_CMP_MASKED_EQ == rule->args_value[i].op)
461 arg_cmp[i] = SCMP_CMP(rule->args_value[i].index, rule->args_value[i].op, rule->args_value[i].mask, rule->args_value[i].value);
462 else
463 arg_cmp[i] = SCMP_CMP(rule->args_value[i].index, rule->args_value[i].op, rule->args_value[i].value);
464 }
465
466 ret = seccomp_rule_add_exact_array(ctx, rule->action, nr, rule->args_num, arg_cmp);
467 if (ret < 0) {
468 ERROR("Failed (%d) loading rule for %s (nr %d action %d(%s)): %s",
469 ret, line, nr, rule->action, get_action_name(rule->action), strerror(-ret));
470 return false;
471 }
472 return true;
473 }
474
475 /*
476 * v2 consists of
477 * [x86]
478 * open
479 * read
480 * write
481 * close
482 * # a comment
483 * [x86_64]
484 * open
485 * read
486 * write
487 * close
488 */
489 static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
490 {
491 char *p;
492 int ret;
493 scmp_filter_ctx compat_ctx[2] = {NULL, NULL};
494 bool blacklist = false;
495 uint32_t default_policy_action = -1, default_rule_action = -1;
496 enum lxc_hostarch_t native_arch = get_hostarch(),
497 cur_rule_arch = native_arch;
498 uint32_t compat_arch[2] = {SCMP_ARCH_NATIVE, SCMP_ARCH_NATIVE};
499 struct seccomp_v2_rule rule;
500
501 if (strncmp(line, "blacklist", 9) == 0)
502 blacklist = true;
503 else if (strncmp(line, "whitelist", 9) != 0) {
504 ERROR("Bad seccomp policy style: %s", line);
505 return -1;
506 }
507
508 if ((p = strchr(line, ' '))) {
509 default_policy_action = get_v2_default_action(p + 1);
510 if (default_policy_action == -2)
511 return -1;
512 }
513
514 /* for blacklist, allow any syscall which has no rule */
515 if (blacklist) {
516 if (default_policy_action == -1)
517 default_policy_action = SCMP_ACT_ALLOW;
518 if (default_rule_action == -1)
519 default_rule_action = SCMP_ACT_KILL;
520 } else {
521 if (default_policy_action == -1)
522 default_policy_action = SCMP_ACT_KILL;
523 if (default_rule_action == -1)
524 default_rule_action = SCMP_ACT_ALLOW;
525 }
526
527 if (native_arch == lxc_seccomp_arch_amd64) {
528 cur_rule_arch = lxc_seccomp_arch_all;
529 compat_arch[0] = SCMP_ARCH_X86;
530 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_i386,
531 default_policy_action);
532 compat_arch[1] = SCMP_ARCH_X32;
533 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_x32,
534 default_policy_action);
535 if (!compat_ctx[0] || !compat_ctx[1])
536 goto bad;
537 #ifdef SCMP_ARCH_PPC
538 } else if (native_arch == lxc_seccomp_arch_ppc64) {
539 cur_rule_arch = lxc_seccomp_arch_all;
540 compat_arch[0] = SCMP_ARCH_PPC;
541 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_ppc,
542 default_policy_action);
543 if (!compat_ctx[0])
544 goto bad;
545 #endif
546 #ifdef SCMP_ARCH_ARM
547 } else if (native_arch == lxc_seccomp_arch_arm64) {
548 cur_rule_arch = lxc_seccomp_arch_all;
549 compat_arch[0] = SCMP_ARCH_ARM;
550 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_arm,
551 default_policy_action);
552 if (!compat_ctx[0])
553 goto bad;
554 #endif
555 #ifdef SCMP_ARCH_MIPS
556 } else if (native_arch == lxc_seccomp_arch_mips64) {
557 cur_rule_arch = lxc_seccomp_arch_all;
558 compat_arch[0] = SCMP_ARCH_MIPS;
559 compat_arch[1] = SCMP_ARCH_MIPS64N32;
560 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mips,
561 default_policy_action);
562 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mips64n32,
563 default_policy_action);
564 if (!compat_ctx[0] || !compat_ctx[1])
565 goto bad;
566 } else if (native_arch == lxc_seccomp_arch_mipsel64) {
567 cur_rule_arch = lxc_seccomp_arch_all;
568 compat_arch[0] = SCMP_ARCH_MIPSEL;
569 compat_arch[1] = SCMP_ARCH_MIPSEL64N32;
570 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mipsel,
571 default_policy_action);
572 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32,
573 default_policy_action);
574 if (!compat_ctx[0] || !compat_ctx[1])
575 goto bad;
576 #endif
577 }
578
579 if (default_policy_action != SCMP_ACT_KILL) {
580 ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
581 if (ret != 0) {
582 ERROR("Error re-initializing Seccomp");
583 return -1;
584 }
585 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) {
586 ERROR("Failed to turn off no-new-privs");
587 return -1;
588 }
589 #ifdef SCMP_FLTATR_ATL_TSKIP
590 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
591 WARN("Failed to turn on seccomp nop-skip, continuing");
592 }
593 #endif
594 }
595
596 while (fgets(line, 1024, f)) {
597
598 if (line[0] == '#')
599 continue;
600 if (strlen(line) == 0)
601 continue;
602 remove_trailing_newlines(line);
603 INFO("processing: .%s", line);
604 if (line[0] == '[') {
605 /* Read the architecture for next set of rules. */
606 if (strcmp(line, "[x86]") == 0 ||
607 strcmp(line, "[X86]") == 0) {
608 if (native_arch != lxc_seccomp_arch_i386 &&
609 native_arch != lxc_seccomp_arch_amd64) {
610 cur_rule_arch = lxc_seccomp_arch_unknown;
611 continue;
612 }
613 cur_rule_arch = lxc_seccomp_arch_i386;
614 } else if (strcmp(line, "[x32]") == 0 ||
615 strcmp(line, "[X32]") == 0) {
616 if (native_arch != lxc_seccomp_arch_amd64) {
617 cur_rule_arch = lxc_seccomp_arch_unknown;
618 continue;
619 }
620 cur_rule_arch = lxc_seccomp_arch_x32;
621 } else if (strcmp(line, "[X86_64]") == 0 ||
622 strcmp(line, "[x86_64]") == 0) {
623 if (native_arch != lxc_seccomp_arch_amd64) {
624 cur_rule_arch = lxc_seccomp_arch_unknown;
625 continue;
626 }
627 cur_rule_arch = lxc_seccomp_arch_amd64;
628 } else if (strcmp(line, "[all]") == 0 ||
629 strcmp(line, "[ALL]") == 0) {
630 cur_rule_arch = lxc_seccomp_arch_all;
631 }
632 #ifdef SCMP_ARCH_ARM
633 else if (strcmp(line, "[arm]") == 0 ||
634 strcmp(line, "[ARM]") == 0) {
635 if (native_arch != lxc_seccomp_arch_arm &&
636 native_arch != lxc_seccomp_arch_arm64) {
637 cur_rule_arch = lxc_seccomp_arch_unknown;
638 continue;
639 }
640 cur_rule_arch = lxc_seccomp_arch_arm;
641 }
642 #endif
643 #ifdef SCMP_ARCH_AARCH64
644 else if (strcmp(line, "[arm64]") == 0 ||
645 strcmp(line, "[ARM64]") == 0) {
646 if (native_arch != lxc_seccomp_arch_arm64) {
647 cur_rule_arch = lxc_seccomp_arch_unknown;
648 continue;
649 }
650 cur_rule_arch = lxc_seccomp_arch_arm64;
651 }
652 #endif
653 #ifdef SCMP_ARCH_PPC64LE
654 else if (strcmp(line, "[ppc64le]") == 0 ||
655 strcmp(line, "[PPC64LE]") == 0) {
656 if (native_arch != lxc_seccomp_arch_ppc64le) {
657 cur_rule_arch = lxc_seccomp_arch_unknown;
658 continue;
659 }
660 cur_rule_arch = lxc_seccomp_arch_ppc64le;
661 }
662 #endif
663 #ifdef SCMP_ARCH_PPC64
664 else if (strcmp(line, "[ppc64]") == 0 ||
665 strcmp(line, "[PPC64]") == 0) {
666 if (native_arch != lxc_seccomp_arch_ppc64) {
667 cur_rule_arch = lxc_seccomp_arch_unknown;
668 continue;
669 }
670 cur_rule_arch = lxc_seccomp_arch_ppc64;
671 }
672 #endif
673 #ifdef SCMP_ARCH_PPC
674 else if (strcmp(line, "[ppc]") == 0 ||
675 strcmp(line, "[PPC]") == 0) {
676 if (native_arch != lxc_seccomp_arch_ppc &&
677 native_arch != lxc_seccomp_arch_ppc64) {
678 cur_rule_arch = lxc_seccomp_arch_unknown;
679 continue;
680 }
681 cur_rule_arch = lxc_seccomp_arch_ppc;
682 }
683 #endif
684 #ifdef SCMP_ARCH_MIPS
685 else if (strcmp(line, "[mips64]") == 0 ||
686 strcmp(line, "[MIPS64]") == 0) {
687 if (native_arch != lxc_seccomp_arch_mips64) {
688 cur_rule_arch = lxc_seccomp_arch_unknown;
689 continue;
690 }
691 cur_rule_arch = lxc_seccomp_arch_mips64;
692 } else if (strcmp(line, "[mips64n32]") == 0 ||
693 strcmp(line, "[MIPS64N32]") == 0) {
694 if (native_arch != lxc_seccomp_arch_mips64) {
695 cur_rule_arch = lxc_seccomp_arch_unknown;
696 continue;
697 }
698 cur_rule_arch = lxc_seccomp_arch_mips64n32;
699 } else if (strcmp(line, "[mips]") == 0 ||
700 strcmp(line, "[MIPS]") == 0) {
701 if (native_arch != lxc_seccomp_arch_mips &&
702 native_arch != lxc_seccomp_arch_mips64) {
703 cur_rule_arch = lxc_seccomp_arch_unknown;
704 continue;
705 }
706 cur_rule_arch = lxc_seccomp_arch_mips;
707 } else if (strcmp(line, "[mipsel64]") == 0 ||
708 strcmp(line, "[MIPSEL64]") == 0) {
709 if (native_arch != lxc_seccomp_arch_mipsel64) {
710 cur_rule_arch = lxc_seccomp_arch_unknown;
711 continue;
712 }
713 cur_rule_arch = lxc_seccomp_arch_mipsel64;
714 } else if (strcmp(line, "[mipsel64n32]") == 0 ||
715 strcmp(line, "[MIPSEL64N32]") == 0) {
716 if (native_arch != lxc_seccomp_arch_mipsel64) {
717 cur_rule_arch = lxc_seccomp_arch_unknown;
718 continue;
719 }
720 cur_rule_arch = lxc_seccomp_arch_mipsel64n32;
721 } else if (strcmp(line, "[mipsel]") == 0 ||
722 strcmp(line, "[MIPSEL]") == 0) {
723 if (native_arch != lxc_seccomp_arch_mipsel &&
724 native_arch != lxc_seccomp_arch_mipsel64) {
725 cur_rule_arch = lxc_seccomp_arch_unknown;
726 continue;
727 }
728 cur_rule_arch = lxc_seccomp_arch_mipsel;
729 }
730 #endif
731 #ifdef SCMP_ARCH_S390X
732 else if (strcmp(line, "[s390x]") == 0 ||
733 strcmp(line, "[S390X]") == 0) {
734 if (native_arch != lxc_seccomp_arch_s390x) {
735 cur_rule_arch = lxc_seccomp_arch_unknown;
736 continue;
737 }
738 cur_rule_arch = lxc_seccomp_arch_s390x;
739 }
740 #endif
741 else
742 goto bad_arch;
743
744 continue;
745 }
746
747 /* irrelevant arch - i.e. arm on i386 */
748 if (cur_rule_arch == lxc_seccomp_arch_unknown)
749 continue;
750
751 memset(&rule, 0, sizeof(rule));
752 /* read optional action which follows the syscall */
753 ret = parse_v2_rules(line, default_rule_action, &rule);
754 if (ret != 0) {
755 ERROR("Failed to interpret seccomp rule");
756 goto bad_rule;
757 }
758
759 if (cur_rule_arch == native_arch ||
760 cur_rule_arch == lxc_seccomp_arch_native ||
761 compat_arch[0] == SCMP_ARCH_NATIVE) {
762 INFO("Adding native rule for %s action %d(%s)", line, rule.action,
763 get_action_name(rule.action));
764 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, &rule))
765 goto bad_rule;
766 }
767 else if (cur_rule_arch != lxc_seccomp_arch_all) {
768 int arch_index =
769 cur_rule_arch == lxc_seccomp_arch_mips64n32 ||
770 cur_rule_arch == lxc_seccomp_arch_mipsel64n32 ? 1 : 0;
771
772 INFO("Adding compat-only rule for %s action %d(%s)", line, rule.action,
773 get_action_name(rule.action));
774 if (!do_resolve_add_rule(compat_arch[arch_index], line, compat_ctx[arch_index], &rule))
775 goto bad_rule;
776 }
777 else {
778 INFO("Adding native rule for %s action %d(%s)", line, rule.action,
779 get_action_name(rule.action));
780 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, &rule))
781 goto bad_rule;
782 INFO("Adding compat rule for %s action %d(%s)", line, rule.action,
783 get_action_name(rule.action));
784 if (!do_resolve_add_rule(compat_arch[0], line, compat_ctx[0], &rule))
785 goto bad_rule;
786 if (compat_arch[1] != SCMP_ARCH_NATIVE &&
787 !do_resolve_add_rule(compat_arch[1], line, compat_ctx[1], &rule))
788 goto bad_rule;
789 }
790 }
791
792 INFO("Merging compat seccomp contexts into main context");
793 if (compat_ctx[0]) {
794 if ((compat_arch[0] != native_arch) &&
795 (compat_arch[0] != seccomp_arch_native())) {
796 ret = seccomp_merge(conf->seccomp_ctx, compat_ctx[0]);
797 if (ret < 0) {
798 ERROR("Failed to merge first compat seccomp "
799 "context into main context");
800 goto bad;
801 }
802 TRACE("Merged first compat seccomp context into main context");
803 } else {
804 seccomp_release(compat_ctx[0]);
805 compat_ctx[0] = NULL;
806 }
807 }
808
809 if (compat_ctx[1]) {
810 if ((compat_arch[1] != native_arch) &&
811 (compat_arch[1] != seccomp_arch_native())) {
812 ret = seccomp_merge(conf->seccomp_ctx, compat_ctx[1]);
813 if (ret < 0) {
814 ERROR("Failed to merge first compat seccomp "
815 "context into main context");
816 goto bad;
817 }
818 TRACE("Merged second compat seccomp context into main context");
819 } else {
820 seccomp_release(compat_ctx[1]);
821 compat_ctx[1] = NULL;
822 }
823 }
824
825 return 0;
826
827 bad_arch:
828 ERROR("Unsupported arch: %s.", line);
829 bad_rule:
830 bad:
831 if (compat_ctx[0])
832 seccomp_release(compat_ctx[0]);
833 if (compat_ctx[1])
834 seccomp_release(compat_ctx[1]);
835 return -1;
836 }
837 #else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
838 static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
839 {
840 return -1;
841 }
842 #endif /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
843
844 /*
845 * The first line of the config file has a policy language version
846 * the second line has some directives
847 * then comes policy subject to the directives
848 * right now version must be '1' or '2'
849 * the directives must include 'whitelist'(version == 1 or 2) or 'blacklist'
850 * (version == 2) and can include 'debug' (though debug is not yet supported).
851 */
852 static int parse_config(FILE *f, struct lxc_conf *conf)
853 {
854 char line[1024];
855 int ret, version;
856
857 ret = fscanf(f, "%d\n", &version);
858 if (ret != 1 || (version != 1 && version != 2)) {
859 ERROR("Invalid version");
860 return -1;
861 }
862 if (!fgets(line, 1024, f)) {
863 ERROR("Invalid config file");
864 return -1;
865 }
866 if (version == 1 && !strstr(line, "whitelist")) {
867 ERROR("Only whitelist policy is supported");
868 return -1;
869 }
870
871 if (strstr(line, "debug")) {
872 ERROR("Debug not yet implemented");
873 return -1;
874 }
875
876 if (version == 1)
877 return parse_config_v1(f, conf);
878 return parse_config_v2(f, line, conf);
879 }
880
881 /*
882 * use_seccomp: return true if we should try and apply a seccomp policy
883 * if defined for the container.
884 * This will return false if
885 * 1. seccomp is not enabled in the kernel
886 * 2. a seccomp policy is already enabled for this task
887 */
888 static bool use_seccomp(void)
889 {
890 FILE *f = fopen("/proc/self/status", "r");
891 char line[1024];
892 bool already_enabled = false;
893 bool found = false;
894 int ret, v;
895
896 if (!f)
897 return true;
898
899 while (fgets(line, 1024, f)) {
900 if (strncmp(line, "Seccomp:", 8) == 0) {
901 found = true;
902 ret = sscanf(line + 8, "%d", &v);
903 if (ret == 1 && v != 0)
904 already_enabled = true;
905 break;
906 }
907 }
908
909 fclose(f);
910 if (!found) { /* no Seccomp line, no seccomp in kernel */
911 INFO("Seccomp is not enabled in the kernel");
912 return false;
913 }
914 if (already_enabled) { /* already seccomp-confined */
915 INFO("Already seccomp-confined, not loading new policy");
916 return false;
917 }
918 return true;
919 }
920
921 int lxc_read_seccomp_config(struct lxc_conf *conf)
922 {
923 FILE *f;
924 int ret;
925 int check_seccomp_attr_set;
926
927 if (!conf->seccomp)
928 return 0;
929
930 if (!use_seccomp())
931 return 0;
932 #if HAVE_SCMP_FILTER_CTX
933 /* XXX for debug, pass in SCMP_ACT_TRAP */
934 conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL);
935 ret = !conf->seccomp_ctx;
936 #else
937 ret = seccomp_init(SCMP_ACT_KILL) < 0;
938 #endif
939 if (ret) {
940 ERROR("Failed initializing seccomp");
941 return -1;
942 }
943
944 /* turn off no-new-privs. We don't want it in lxc, and it breaks
945 * with apparmor */
946 #if HAVE_SCMP_FILTER_CTX
947 check_seccomp_attr_set = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
948 #else
949 check_seccomp_attr_set = seccomp_attr_set(SCMP_FLTATR_CTL_NNP, 0);
950 #endif
951 if (check_seccomp_attr_set) {
952 ERROR("Failed to turn off no-new-privs");
953 return -1;
954 }
955 #ifdef SCMP_FLTATR_ATL_TSKIP
956 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
957 WARN("Failed to turn on seccomp nop-skip, continuing");
958 }
959 #endif
960
961 f = fopen(conf->seccomp, "r");
962 if (!f) {
963 SYSERROR("Failed to open seccomp policy file %s", conf->seccomp);
964 return -1;
965 }
966 ret = parse_config(f, conf);
967 fclose(f);
968 return ret;
969 }
970
971 int lxc_seccomp_load(struct lxc_conf *conf)
972 {
973 int ret;
974 if (!conf->seccomp)
975 return 0;
976 if (!use_seccomp())
977 return 0;
978 ret = seccomp_load(
979 #if HAVE_SCMP_FILTER_CTX
980 conf->seccomp_ctx
981 #endif
982 );
983 if (ret < 0) {
984 ERROR("Error loading the seccomp policy: %s", strerror(-ret));
985 return -1;
986 }
987
988 /* After load seccomp filter into the kernel successfully, export the current seccomp
989 * filter to log file */
990 #if HAVE_SCMP_FILTER_CTX
991 if ((lxc_log_get_level() <= LXC_LOG_LEVEL_TRACE || conf->loglevel <= LXC_LOG_LEVEL_TRACE) &&
992 lxc_log_fd >= 0) {
993 ret = seccomp_export_pfc(conf->seccomp_ctx, lxc_log_fd);
994 /* Just give an warning when export error */
995 if (ret < 0)
996 WARN("Failed to export seccomp filter to log file: %s", strerror(-ret));
997 }
998 #endif
999 return 0;
1000 }
1001
1002 void lxc_seccomp_free(struct lxc_conf *conf)
1003 {
1004 free(conf->seccomp);
1005 conf->seccomp = NULL;
1006 #if HAVE_SCMP_FILTER_CTX
1007 if (conf->seccomp_ctx) {
1008 seccomp_release(conf->seccomp_ctx);
1009 conf->seccomp_ctx = NULL;
1010 }
1011 #endif
1012 }