2 * lxc: linux Container library
4 * (C) Copyright Canonical, Inc. 2012
7 * Serge Hallyn <serge.hallyn@canonical.com>
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.
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.
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
29 #include <sys/mount.h>
30 #include <sys/utsname.h>
34 #include "lxcseccomp.h"
36 lxc_log_define(lxc_seccomp
, lxc
);
38 static int parse_config_v1(FILE *f
, struct lxc_conf
*conf
)
43 while (fgets(line
, 1024, f
)) {
45 ret
= sscanf(line
, "%d", &nr
);
48 ret
= seccomp_rule_add(
49 #if HAVE_SCMP_FILTER_CTX
52 SCMP_ACT_ALLOW
, nr
, 0);
54 ERROR("Failed loading allow rule for %d", nr
);
61 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
62 static void remove_trailing_newlines(char *l
)
68 while (--p
>= l
&& *p
== '\n')
72 static uint32_t get_v2_default_action(char *line
)
74 uint32_t ret_action
= -1;
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) {
83 if (sscanf(line
+ 5, "%d", &e
) != 1) {
84 ERROR("Bad errno value in %s", line
);
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
;
95 static const char *get_action_name(uint32_t action
)
97 /* The upper 16 bits indicate the type of the seccomp action. */
98 switch(action
& 0xffff0000){
105 case SCMP_ACT_ERRNO(0):
108 return "invalid action";
112 static uint32_t get_v2_action(char *line
, uint32_t def_action
)
114 char *p
= strchr(line
, ' ');
122 if (!*p
|| *p
== '#')
124 ret
= get_v2_default_action(p
);
127 case -1: return def_action
;
132 struct v2_rule_args
{
136 enum scmp_compare op
;
139 struct seccomp_v2_rule
{
142 struct v2_rule_args args_value
[6];
145 static enum scmp_compare
parse_v2_rule_op(char *s
)
147 if (strcmp(s
, "SCMP_CMP_NE") == 0 || strcmp(s
, "!=") == 0)
149 else if (strcmp(s
, "SCMP_CMP_LT") == 0 || strcmp(s
, "<") == 0)
151 else if (strcmp(s
, "SCMP_CMP_LE") == 0 || strcmp(s
, "<=") == 0)
153 else if (strcmp(s
, "SCMP_CMP_EQ") == 0 || strcmp(s
, "==") == 0)
155 else if (strcmp(s
, "SCMP_CMP_GE") == 0 || strcmp(s
, ">=") == 0)
157 else if (strcmp(s
, "SCMP_CMP_GT") == 0 || strcmp(s
, ">") == 0)
159 else if (strcmp(s
, "SCMP_CMP_MASKED_EQ") == 0 || strcmp(s
, "&=") == 0)
160 return SCMP_CMP_MASKED_EQ
;
162 return _SCMP_CMP_MAX
;
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.
177 static int get_seccomp_arg_value(char *key
, struct v2_rule_args
*rule_args
)
182 enum scmp_compare op
= 0;
187 memset(s
, 0, sizeof(s
));
188 tmp
= strchr(key
, '[');
190 ERROR("Failed to interpret args");
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");
199 op
= parse_v2_rule_op(s
);
200 if (op
== _SCMP_CMP_MAX
) {
201 ERROR("Failed to interpret args operator value");
205 rule_args
->index
= index
;
206 rule_args
->value
= value
;
207 rule_args
->mask
= mask
;
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.
218 static int parse_v2_rules(char *line
, uint32_t def_action
, struct seccomp_v2_rule
*rules
)
224 char *saveptr
= NULL
;
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");
239 if (!strchr(tmp
, '[')) {
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
]);
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,
284 # define MIPS_ARCH_O32 lxc_seccomp_arch_mipsel
285 # define MIPS_ARCH_N64 lxc_seccomp_arch_mipsel64
287 # define MIPS_ARCH_O32 lxc_seccomp_arch_mips
288 # define MIPS_ARCH_N64 lxc_seccomp_arch_mips64
291 int get_hostarch(void)
294 if (uname(&uts
) < 0) {
295 SYSERROR("Failed to read host arch");
298 if (strcmp(uts
.machine
, "i686") == 0)
299 return lxc_seccomp_arch_i386
;
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
;
322 scmp_filter_ctx
get_new_ctx(enum lxc_hostarch_t n_arch
, uint32_t default_policy_action
)
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;
336 #ifdef SCMP_ARCH_PPC64LE
337 case lxc_seccomp_arch_ppc64le
: arch
= SCMP_ARCH_PPC64LE
; break;
339 #ifdef SCMP_ARCH_PPC64
340 case lxc_seccomp_arch_ppc64
: arch
= SCMP_ARCH_PPC64
; break;
343 case lxc_seccomp_arch_ppc
: arch
= SCMP_ARCH_PPC
; break;
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;
353 #ifdef SCMP_ARCH_S390X
354 case lxc_seccomp_arch_s390x
: arch
= SCMP_ARCH_S390X
; break;
356 default: return NULL
;
359 if ((ctx
= seccomp_init(default_policy_action
)) == NULL
) {
360 ERROR("Error initializing seccomp context");
363 if (seccomp_attr_set(ctx
, SCMP_FLTATR_CTL_NNP
, 0)) {
364 ERROR("Failed to turn off no-new-privs");
365 seccomp_release(ctx
);
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");
374 ret
= seccomp_arch_exist(ctx
, arch
);
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
);
384 ret
= seccomp_arch_add(ctx
, arch
);
386 ERROR("%s - Failed to add arch %d to main seccomp context",
387 strerror(-ret
), (int)n_arch
);
388 seccomp_release(ctx
);
391 TRACE("Added arch %d to main seccomp context", (int)n_arch
);
393 ret
= seccomp_arch_remove(ctx
, SCMP_ARCH_NATIVE
);
395 ERROR("Failed to remove native arch from main seccomp context");
396 seccomp_release(ctx
);
399 TRACE("Removed native arch from main seccomp context");
401 TRACE("Arch %d already present in main seccomp context", (int)n_arch
);
407 bool do_resolve_add_rule(uint32_t arch
, char *line
, scmp_filter_ctx ctx
,
408 struct seccomp_v2_rule
*rule
)
411 struct scmp_arg_cmp arg_cmp
[6];
413 memset(arg_cmp
, 0 ,sizeof(arg_cmp
));
415 ret
= seccomp_arch_exist(ctx
, arch
);
416 if (arch
&& ret
!= 0) {
417 ERROR("BUG: Seccomp: rule and context arch do not match (arch "
419 arch
, strerror(-ret
));
423 /*get the syscall name*/
424 char *p
= strchr(line
, ' ');
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
));
433 ERROR("Failed (%d) loading rule to reject force "
435 ret
, strerror(-ret
));
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");
448 WARN("Seccomp: got negative for syscall: %d: %s", nr
, line
);
449 WARN("This syscall will NOT be blacklisted");
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
);
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
);
463 arg_cmp
[i
] = SCMP_CMP(rule
->args_value
[i
].index
, rule
->args_value
[i
].op
, rule
->args_value
[i
].value
);
466 ret
= seccomp_rule_add_exact_array(ctx
, rule
->action
, nr
, rule
->args_num
, arg_cmp
);
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
));
489 static int parse_config_v2(FILE *f
, char *line
, struct lxc_conf
*conf
)
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
;
501 if (strncmp(line
, "blacklist", 9) == 0)
503 else if (strncmp(line
, "whitelist", 9) != 0) {
504 ERROR("Bad seccomp policy style: %s", line
);
508 if ((p
= strchr(line
, ' '))) {
509 default_policy_action
= get_v2_default_action(p
+ 1);
510 if (default_policy_action
== -2)
514 /* for blacklist, allow any syscall which has no rule */
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
;
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
;
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])
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
);
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
);
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])
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])
579 if (default_policy_action
!= SCMP_ACT_KILL
) {
580 ret
= seccomp_reset(conf
->seccomp_ctx
, default_policy_action
);
582 ERROR("Error re-initializing Seccomp");
585 if (seccomp_attr_set(conf
->seccomp_ctx
, SCMP_FLTATR_CTL_NNP
, 0)) {
586 ERROR("Failed to turn off no-new-privs");
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");
596 while (fgets(line
, 1024, f
)) {
600 if (strlen(line
) == 0)
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
;
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
;
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
;
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
;
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
;
640 cur_rule_arch
= lxc_seccomp_arch_arm
;
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
;
650 cur_rule_arch
= lxc_seccomp_arch_arm64
;
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
;
660 cur_rule_arch
= lxc_seccomp_arch_ppc64le
;
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
;
670 cur_rule_arch
= lxc_seccomp_arch_ppc64
;
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
;
681 cur_rule_arch
= lxc_seccomp_arch_ppc
;
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
;
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
;
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
;
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
;
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
;
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
;
728 cur_rule_arch
= lxc_seccomp_arch_mipsel
;
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
;
738 cur_rule_arch
= lxc_seccomp_arch_s390x
;
747 /* irrelevant arch - i.e. arm on i386 */
748 if (cur_rule_arch
== lxc_seccomp_arch_unknown
)
751 memset(&rule
, 0, sizeof(rule
));
752 /* read optional action which follows the syscall */
753 ret
= parse_v2_rules(line
, default_rule_action
, &rule
);
755 ERROR("Failed to interpret seccomp rule");
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
))
767 else if (cur_rule_arch
!= lxc_seccomp_arch_all
) {
769 cur_rule_arch
== lxc_seccomp_arch_mips64n32
||
770 cur_rule_arch
== lxc_seccomp_arch_mipsel64n32
? 1 : 0;
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
))
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
))
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
))
786 if (compat_arch
[1] != SCMP_ARCH_NATIVE
&&
787 !do_resolve_add_rule(compat_arch
[1], line
, compat_ctx
[1], &rule
))
792 INFO("Merging compat seccomp contexts into main context");
794 if ((compat_arch
[0] != native_arch
) &&
795 (compat_arch
[0] != seccomp_arch_native())) {
796 ret
= seccomp_merge(conf
->seccomp_ctx
, compat_ctx
[0]);
798 ERROR("Failed to merge first compat seccomp "
799 "context into main context");
802 TRACE("Merged first compat seccomp context into main context");
804 seccomp_release(compat_ctx
[0]);
805 compat_ctx
[0] = NULL
;
810 if ((compat_arch
[1] != native_arch
) &&
811 (compat_arch
[1] != seccomp_arch_native())) {
812 ret
= seccomp_merge(conf
->seccomp_ctx
, compat_ctx
[1]);
814 ERROR("Failed to merge first compat seccomp "
815 "context into main context");
818 TRACE("Merged second compat seccomp context into main context");
820 seccomp_release(compat_ctx
[1]);
821 compat_ctx
[1] = NULL
;
828 ERROR("Unsupported arch: %s.", line
);
832 seccomp_release(compat_ctx
[0]);
834 seccomp_release(compat_ctx
[1]);
837 #else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
838 static int parse_config_v2(FILE *f
, char *line
, struct lxc_conf
*conf
)
842 #endif /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
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).
852 static int parse_config(FILE *f
, struct lxc_conf
*conf
)
857 ret
= fscanf(f
, "%d\n", &version
);
858 if (ret
!= 1 || (version
!= 1 && version
!= 2)) {
859 ERROR("Invalid version");
862 if (!fgets(line
, 1024, f
)) {
863 ERROR("Invalid config file");
866 if (version
== 1 && !strstr(line
, "whitelist")) {
867 ERROR("Only whitelist policy is supported");
871 if (strstr(line
, "debug")) {
872 ERROR("Debug not yet implemented");
877 return parse_config_v1(f
, conf
);
878 return parse_config_v2(f
, line
, conf
);
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
888 static bool use_seccomp(void)
890 FILE *f
= fopen("/proc/self/status", "r");
892 bool already_enabled
= false;
899 while (fgets(line
, 1024, f
)) {
900 if (strncmp(line
, "Seccomp:", 8) == 0) {
902 ret
= sscanf(line
+ 8, "%d", &v
);
903 if (ret
== 1 && v
!= 0)
904 already_enabled
= true;
910 if (!found
) { /* no Seccomp line, no seccomp in kernel */
911 INFO("Seccomp is not enabled in the kernel");
914 if (already_enabled
) { /* already seccomp-confined */
915 INFO("Already seccomp-confined, not loading new policy");
921 int lxc_read_seccomp_config(struct lxc_conf
*conf
)
925 int check_seccomp_attr_set
;
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
;
937 ret
= seccomp_init(SCMP_ACT_KILL
) < 0;
940 ERROR("Failed initializing seccomp");
944 /* turn off no-new-privs. We don't want it in lxc, and it breaks
946 #if HAVE_SCMP_FILTER_CTX
947 check_seccomp_attr_set
= seccomp_attr_set(conf
->seccomp_ctx
, SCMP_FLTATR_CTL_NNP
, 0);
949 check_seccomp_attr_set
= seccomp_attr_set(SCMP_FLTATR_CTL_NNP
, 0);
951 if (check_seccomp_attr_set
) {
952 ERROR("Failed to turn off no-new-privs");
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");
961 f
= fopen(conf
->seccomp
, "r");
963 SYSERROR("Failed to open seccomp policy file %s", conf
->seccomp
);
966 ret
= parse_config(f
, conf
);
971 int lxc_seccomp_load(struct lxc_conf
*conf
)
979 #if HAVE_SCMP_FILTER_CTX
984 ERROR("Error loading the seccomp policy: %s", strerror(-ret
));
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
) &&
993 ret
= seccomp_export_pfc(conf
->seccomp_ctx
, lxc_log_fd
);
994 /* Just give an warning when export error */
996 WARN("Failed to export seccomp filter to log file: %s", strerror(-ret
));
1002 void lxc_seccomp_free(struct lxc_conf
*conf
)
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
;