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
31 #include <sys/mount.h>
32 #include <sys/utsname.h>
36 #include "lxccontainer.h"
37 #include "lxcseccomp.h"
38 #include "memory_utils.h"
42 #define MIPS_ARCH_O32 lxc_seccomp_arch_mipsel
43 #define MIPS_ARCH_N64 lxc_seccomp_arch_mipsel64
45 #define MIPS_ARCH_O32 lxc_seccomp_arch_mips
46 #define MIPS_ARCH_N64 lxc_seccomp_arch_mips64
49 lxc_log_define(seccomp
, lxc
);
51 static int parse_config_v1(FILE *f
, char *line
, size_t *line_bufsz
, struct lxc_conf
*conf
)
55 while (getline(&line
, line_bufsz
, f
) != -1) {
58 ret
= sscanf(line
, "%d", &nr
);
64 #if HAVE_SCMP_FILTER_CTX
65 ret
= seccomp_rule_add(conf
->seccomp_ctx
, SCMP_ACT_ALLOW
, nr
, 0);
67 ret
= seccomp_rule_add(SCMP_ACT_ALLOW
, nr
, 0);
70 ERROR("Failed loading allow rule for %d", nr
);
79 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
80 static const char *get_action_name(uint32_t action
)
82 /* The upper 16 bits indicate the type of the seccomp action. */
83 switch (action
& 0xffff0000) {
90 case SCMP_ACT_ERRNO(0):
92 #if HAVE_DECL_SECCOMP_NOTIF_GET_FD
93 case SCMP_ACT_USER_NOTIF
:
98 return "invalid action";
101 static uint32_t get_v2_default_action(char *line
)
103 uint32_t ret_action
= -1;
108 /* After 'whitelist' or 'blacklist' comes default behavior. */
109 if (strncmp(line
, "kill", 4) == 0) {
110 ret_action
= SCMP_ACT_KILL
;
111 } else if (strncmp(line
, "errno", 5) == 0) {
114 ret
= sscanf(line
+ 5, "%d", &e
);
116 ERROR("Failed to parse errno value from %s", line
);
120 ret_action
= SCMP_ACT_ERRNO(e
);
121 } else if (strncmp(line
, "allow", 5) == 0) {
122 ret_action
= SCMP_ACT_ALLOW
;
123 } else if (strncmp(line
, "trap", 4) == 0) {
124 ret_action
= SCMP_ACT_TRAP
;
125 #if HAVE_DECL_SECCOMP_NOTIF_GET_FD
126 } else if (strncmp(line
, "notify", 6) == 0) {
127 ret_action
= SCMP_ACT_USER_NOTIF
;
129 } else if (line
[0]) {
130 ERROR("Unrecognized seccomp action \"%s\"", line
);
137 static uint32_t get_v2_action(char *line
, uint32_t def_action
)
142 p
= strchr(line
, ' ');
150 if (!*p
|| *p
== '#')
153 ret
= get_v2_default_action(p
);
164 struct seccomp_v2_rule_args
{
168 enum scmp_compare op
;
171 struct seccomp_v2_rule
{
174 struct seccomp_v2_rule_args args_value
[6];
177 static enum scmp_compare
parse_v2_rule_op(char *s
)
179 if (strcmp(s
, "SCMP_CMP_NE") == 0 || strcmp(s
, "!=") == 0)
181 else if (strcmp(s
, "SCMP_CMP_LT") == 0 || strcmp(s
, "<") == 0)
183 else if (strcmp(s
, "SCMP_CMP_LE") == 0 || strcmp(s
, "<=") == 0)
185 else if (strcmp(s
, "SCMP_CMP_EQ") == 0 || strcmp(s
, "==") == 0)
187 else if (strcmp(s
, "SCMP_CMP_GE") == 0 || strcmp(s
, ">=") == 0)
189 else if (strcmp(s
, "SCMP_CMP_GT") == 0 || strcmp(s
, ">") == 0)
191 else if (strcmp(s
, "SCMP_CMP_MASKED_EQ") == 0 || strcmp(s
, "&=") == 0)
192 return SCMP_CMP_MASKED_EQ
;
194 return _SCMP_CMP_MAX
;
198 * This function is used to parse the args string into the structure.
199 * args string format:[index,value,op,mask] or [index,value,op]
200 * index: the index for syscall arguments (type uint)
201 * value: the value for syscall arguments (type uint64)
202 * op: the operator for syscall arguments(string),
203 a valid list of constants as of libseccomp v2.3.2 is
204 SCMP_CMP_NE,SCMP_CMP_LE,SCMP_CMP_LE, SCMP_CMP_EQ, SCMP_CMP_GE,
205 SCMP_CMP_GT, SCMP_CMP_MASKED_EQ, or !=,<=,==,>=,>,&=
206 * mask: the mask to apply on "value" for SCMP_CMP_MASKED_EQ (type uint64, optional)
207 * Returns 0 on success, < 0 otherwise.
209 static int get_seccomp_arg_value(char *key
, struct seccomp_v2_rule_args
*rule_args
)
213 uint64_t mask
= 0, value
= 0;
214 enum scmp_compare op
= 0;
216 char s
[31] = {0}, v
[24] = {0}, m
[24] = {'0'};
218 tmp
= strchr(key
, '[');
220 ERROR("Failed to interpret args");
224 ret
= sscanf(tmp
, "[%i,%23[^,],%30[^0-9^,],%23[^,]", &index
, v
, s
, m
);
225 if ((ret
!= 3 && ret
!= 4) || index
>= 6) {
226 ERROR("Failed to interpret args value");
230 ret
= lxc_safe_uint64(v
, &value
, 0);
232 ERROR("Invalid argument value");
236 ret
= lxc_safe_uint64(m
, &mask
, 0);
238 ERROR("Invalid argument mask");
242 op
= parse_v2_rule_op(s
);
243 if (op
== _SCMP_CMP_MAX
) {
244 ERROR("Failed to interpret args operator value");
248 rule_args
->index
= index
;
249 rule_args
->value
= value
;
250 rule_args
->mask
= mask
;
255 /* This function is used to parse the seccomp rule entry.
256 * @line : seccomp rule entry string.
257 * @def_action : default action used in the case if the 'line' contain non valid action.
258 * @rules : output struct.
259 * Returns 0 on success, < 0 otherwise.
261 static int parse_v2_rules(char *line
, uint32_t def_action
,
262 struct seccomp_v2_rule
*rules
)
265 char *key
= NULL
, *saveptr
= NULL
, *tmp
= NULL
;
271 /* read optional action which follows the syscall */
272 rules
->action
= get_v2_action(tmp
, def_action
);
273 if (rules
->action
== -1) {
274 ERROR("Failed to interpret action");
281 if (!strchr(tmp
, '['))
285 for ((key
= strtok_r(tmp
, "]", &saveptr
)), i
= 0; key
&& i
< 6;
286 (key
= strtok_r(NULL
, "]", &saveptr
)), i
++) {
287 ret
= get_seccomp_arg_value(key
, &rules
->args_value
[i
]);
303 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
304 enum lxc_hostarch_t
{
305 lxc_seccomp_arch_all
= 0,
306 lxc_seccomp_arch_native
,
307 lxc_seccomp_arch_i386
,
308 lxc_seccomp_arch_x32
,
309 lxc_seccomp_arch_amd64
,
310 lxc_seccomp_arch_arm
,
311 lxc_seccomp_arch_arm64
,
312 lxc_seccomp_arch_ppc64
,
313 lxc_seccomp_arch_ppc64le
,
314 lxc_seccomp_arch_ppc
,
315 lxc_seccomp_arch_mips
,
316 lxc_seccomp_arch_mips64
,
317 lxc_seccomp_arch_mips64n32
,
318 lxc_seccomp_arch_mipsel
,
319 lxc_seccomp_arch_mipsel64
,
320 lxc_seccomp_arch_mipsel64n32
,
321 lxc_seccomp_arch_s390x
,
322 lxc_seccomp_arch_unknown
= 999,
325 int get_hostarch(void)
328 if (uname(&uts
) < 0) {
329 SYSERROR("Failed to read host arch");
333 if (strcmp(uts
.machine
, "i686") == 0)
334 return lxc_seccomp_arch_i386
;
336 else if (strcmp(uts
.machine
, "x86_64") == 0)
337 return lxc_seccomp_arch_amd64
;
338 else if (strncmp(uts
.machine
, "armv7", 5) == 0)
339 return lxc_seccomp_arch_arm
;
340 else if (strncmp(uts
.machine
, "aarch64", 7) == 0)
341 return lxc_seccomp_arch_arm64
;
342 else if (strncmp(uts
.machine
, "ppc64le", 7) == 0)
343 return lxc_seccomp_arch_ppc64le
;
344 else if (strncmp(uts
.machine
, "ppc64", 5) == 0)
345 return lxc_seccomp_arch_ppc64
;
346 else if (strncmp(uts
.machine
, "ppc", 3) == 0)
347 return lxc_seccomp_arch_ppc
;
348 else if (strncmp(uts
.machine
, "mips64", 6) == 0)
349 return MIPS_ARCH_N64
;
350 else if (strncmp(uts
.machine
, "mips", 4) == 0)
351 return MIPS_ARCH_O32
;
352 else if (strncmp(uts
.machine
, "s390x", 5) == 0)
353 return lxc_seccomp_arch_s390x
;
355 return lxc_seccomp_arch_unknown
;
358 scmp_filter_ctx
get_new_ctx(enum lxc_hostarch_t n_arch
,
359 uint32_t default_policy_action
, bool *needs_merge
)
366 case lxc_seccomp_arch_i386
:
367 arch
= SCMP_ARCH_X86
;
369 case lxc_seccomp_arch_x32
:
370 arch
= SCMP_ARCH_X32
;
372 case lxc_seccomp_arch_amd64
:
373 arch
= SCMP_ARCH_X86_64
;
375 case lxc_seccomp_arch_arm
:
376 arch
= SCMP_ARCH_ARM
;
378 #ifdef SCMP_ARCH_AARCH64
379 case lxc_seccomp_arch_arm64
:
380 arch
= SCMP_ARCH_AARCH64
;
383 #ifdef SCMP_ARCH_PPC64LE
384 case lxc_seccomp_arch_ppc64le
:
385 arch
= SCMP_ARCH_PPC64LE
;
388 #ifdef SCMP_ARCH_PPC64
389 case lxc_seccomp_arch_ppc64
:
390 arch
= SCMP_ARCH_PPC64
;
394 case lxc_seccomp_arch_ppc
:
395 arch
= SCMP_ARCH_PPC
;
398 #ifdef SCMP_ARCH_MIPS
399 case lxc_seccomp_arch_mips
:
400 arch
= SCMP_ARCH_MIPS
;
402 case lxc_seccomp_arch_mips64
:
403 arch
= SCMP_ARCH_MIPS64
;
405 case lxc_seccomp_arch_mips64n32
:
406 arch
= SCMP_ARCH_MIPS64N32
;
408 case lxc_seccomp_arch_mipsel
:
409 arch
= SCMP_ARCH_MIPSEL
;
411 case lxc_seccomp_arch_mipsel64
:
412 arch
= SCMP_ARCH_MIPSEL64
;
414 case lxc_seccomp_arch_mipsel64n32
:
415 arch
= SCMP_ARCH_MIPSEL64N32
;
418 #ifdef SCMP_ARCH_S390X
419 case lxc_seccomp_arch_s390x
:
420 arch
= SCMP_ARCH_S390X
;
427 ctx
= seccomp_init(default_policy_action
);
429 ERROR("Error initializing seccomp context");
433 ret
= seccomp_attr_set(ctx
, SCMP_FLTATR_CTL_NNP
, 0);
436 SYSERROR("Failed to turn off no-new-privs");
437 seccomp_release(ctx
);
441 #ifdef SCMP_FLTATR_ATL_TSKIP
442 ret
= seccomp_attr_set(ctx
, SCMP_FLTATR_ATL_TSKIP
, 1);
445 SYSWARN("Failed to turn on seccomp nop-skip, continuing");
449 ret
= seccomp_arch_exist(ctx
, arch
);
451 if (ret
!= -EEXIST
) {
453 SYSERROR("Failed to determine whether arch %d is "
454 "already present in the main seccomp context",
456 seccomp_release(ctx
);
460 ret
= seccomp_arch_add(ctx
, arch
);
463 SYSERROR("Failed to add arch %d to main seccomp context",
465 seccomp_release(ctx
);
468 TRACE("Added arch %d to main seccomp context", (int)n_arch
);
470 ret
= seccomp_arch_remove(ctx
, SCMP_ARCH_NATIVE
);
472 ERROR("Failed to remove native arch from main seccomp context");
473 seccomp_release(ctx
);
476 TRACE("Removed native arch from main seccomp context");
480 *needs_merge
= false;
481 TRACE("Arch %d already present in main seccomp context", (int)n_arch
);
487 bool do_resolve_add_rule(uint32_t arch
, char *line
, scmp_filter_ctx ctx
,
488 struct seccomp_v2_rule
*rule
)
491 struct scmp_arg_cmp arg_cmp
[6];
493 ret
= seccomp_arch_exist(ctx
, arch
);
494 if (arch
&& ret
!= 0) {
496 SYSERROR("Seccomp: rule and context arch do not match (arch %d)", arch
);
500 /*get the syscall name*/
501 char *p
= strchr(line
, ' ');
505 if (strncmp(line
, "reject_force_umount", 19) == 0) {
506 ret
= seccomp_rule_add_exact(ctx
, SCMP_ACT_ERRNO(EACCES
),
507 SCMP_SYS(umount2
), 1,
508 SCMP_A1(SCMP_CMP_MASKED_EQ
, MNT_FORCE
, MNT_FORCE
));
511 SYSERROR("Failed loading rule to reject force umount");
515 INFO("Set seccomp rule to reject force umounts");
519 nr
= seccomp_syscall_resolve_name(line
);
520 if (nr
== __NR_SCMP_ERROR
) {
521 WARN("Failed to resolve syscall \"%s\"", line
);
522 WARN("This syscall will NOT be handled by seccomp");
527 WARN("Got negative return value %d for syscall \"%s\"", nr
, line
);
528 WARN("This syscall will NOT be handled by seccomp");
532 memset(&arg_cmp
, 0, sizeof(arg_cmp
));
533 for (i
= 0; i
< rule
->args_num
; i
++) {
534 INFO("arg_cmp[%d]: SCMP_CMP(%u, %llu, %llu, %llu)", i
,
535 rule
->args_value
[i
].index
,
536 (long long unsigned int)rule
->args_value
[i
].op
,
537 (long long unsigned int)rule
->args_value
[i
].mask
,
538 (long long unsigned int)rule
->args_value
[i
].value
);
540 if (SCMP_CMP_MASKED_EQ
== rule
->args_value
[i
].op
)
541 arg_cmp
[i
] = SCMP_CMP(rule
->args_value
[i
].index
,
542 rule
->args_value
[i
].op
,
543 rule
->args_value
[i
].mask
,
544 rule
->args_value
[i
].value
);
546 arg_cmp
[i
] = SCMP_CMP(rule
->args_value
[i
].index
,
547 rule
->args_value
[i
].op
,
548 rule
->args_value
[i
].value
);
551 ret
= seccomp_rule_add_exact_array(ctx
, rule
->action
, nr
,
552 rule
->args_num
, arg_cmp
);
555 SYSERROR("Failed loading rule for %s (nr %d action %d (%s))",
556 line
, nr
, rule
->action
, get_action_name(rule
->action
));
577 static int parse_config_v2(FILE *f
, char *line
, size_t *line_bufsz
, struct lxc_conf
*conf
)
581 enum lxc_hostarch_t cur_rule_arch
, native_arch
;
582 bool blacklist
= false;
583 uint32_t default_policy_action
= -1, default_rule_action
= -1;
584 struct seccomp_v2_rule rule
;
585 struct scmp_ctx_info
{
586 uint32_t architectures
[3];
587 scmp_filter_ctx contexts
[3];
591 if (strncmp(line
, "blacklist", 9) == 0)
593 else if (strncmp(line
, "whitelist", 9) != 0) {
594 ERROR("Bad seccomp policy style \"%s\"", line
);
598 p
= strchr(line
, ' ');
600 default_policy_action
= get_v2_default_action(p
+ 1);
601 if (default_policy_action
== -2)
605 /* for blacklist, allow any syscall which has no rule */
607 if (default_policy_action
== -1)
608 default_policy_action
= SCMP_ACT_ALLOW
;
610 if (default_rule_action
== -1)
611 default_rule_action
= SCMP_ACT_KILL
;
613 if (default_policy_action
== -1)
614 default_policy_action
= SCMP_ACT_KILL
;
616 if (default_rule_action
== -1)
617 default_rule_action
= SCMP_ACT_ALLOW
;
620 memset(&ctx
, 0, sizeof(ctx
));
621 ctx
.architectures
[0] = SCMP_ARCH_NATIVE
;
622 ctx
.architectures
[1] = SCMP_ARCH_NATIVE
;
623 ctx
.architectures
[2] = SCMP_ARCH_NATIVE
;
624 native_arch
= get_hostarch();
625 cur_rule_arch
= native_arch
;
626 if (native_arch
== lxc_seccomp_arch_amd64
) {
627 cur_rule_arch
= lxc_seccomp_arch_all
;
629 ctx
.architectures
[0] = SCMP_ARCH_X86
;
630 ctx
.contexts
[0] = get_new_ctx(lxc_seccomp_arch_i386
,
631 default_policy_action
,
632 &ctx
.needs_merge
[0]);
633 if (!ctx
.contexts
[0])
636 ctx
.architectures
[1] = SCMP_ARCH_X32
;
637 ctx
.contexts
[1] = get_new_ctx(lxc_seccomp_arch_x32
,
638 default_policy_action
,
639 &ctx
.needs_merge
[1]);
640 if (!ctx
.contexts
[1])
643 ctx
.architectures
[2] = SCMP_ARCH_X86_64
;
644 ctx
.contexts
[2] = get_new_ctx(lxc_seccomp_arch_amd64
,
645 default_policy_action
,
646 &ctx
.needs_merge
[2]);
647 if (!ctx
.contexts
[2])
650 } else if (native_arch
== lxc_seccomp_arch_ppc64
) {
651 cur_rule_arch
= lxc_seccomp_arch_all
;
653 ctx
.architectures
[0] = SCMP_ARCH_PPC
;
654 ctx
.contexts
[0] = get_new_ctx(lxc_seccomp_arch_ppc
,
655 default_policy_action
,
656 &ctx
.needs_merge
[0]);
657 if (!ctx
.contexts
[0])
660 ctx
.architectures
[2] = SCMP_ARCH_PPC64
;
661 ctx
.contexts
[2] = get_new_ctx(lxc_seccomp_arch_ppc64
,
662 default_policy_action
,
663 &ctx
.needs_merge
[2]);
664 if (!ctx
.contexts
[2])
668 } else if (native_arch
== lxc_seccomp_arch_arm64
) {
669 cur_rule_arch
= lxc_seccomp_arch_all
;
671 ctx
.architectures
[0] = SCMP_ARCH_ARM
;
672 ctx
.contexts
[0] = get_new_ctx(lxc_seccomp_arch_arm
,
673 default_policy_action
,
674 &ctx
.needs_merge
[0]);
675 if (!ctx
.contexts
[0])
678 #ifdef SCMP_ARCH_AARCH64
679 ctx
.architectures
[2] = SCMP_ARCH_AARCH64
;
680 ctx
.contexts
[2] = get_new_ctx(lxc_seccomp_arch_arm64
,
681 default_policy_action
,
682 &ctx
.needs_merge
[2]);
683 if (!ctx
.contexts
[2])
687 #ifdef SCMP_ARCH_MIPS
688 } else if (native_arch
== lxc_seccomp_arch_mips64
) {
689 cur_rule_arch
= lxc_seccomp_arch_all
;
691 ctx
.architectures
[0] = SCMP_ARCH_MIPS
;
692 ctx
.contexts
[0] = get_new_ctx(lxc_seccomp_arch_mips
,
693 default_policy_action
,
694 &ctx
.needs_merge
[0]);
695 if (!ctx
.contexts
[0])
698 ctx
.architectures
[1] = SCMP_ARCH_MIPS64N32
;
699 ctx
.contexts
[1] = get_new_ctx(lxc_seccomp_arch_mips64n32
,
700 default_policy_action
,
701 &ctx
.needs_merge
[1]);
702 if (!ctx
.contexts
[1])
705 ctx
.architectures
[2] = SCMP_ARCH_MIPS64
;
706 ctx
.contexts
[2] = get_new_ctx(lxc_seccomp_arch_mips64
,
707 default_policy_action
,
708 &ctx
.needs_merge
[2]);
709 if (!ctx
.contexts
[2])
711 } else if (native_arch
== lxc_seccomp_arch_mipsel64
) {
712 cur_rule_arch
= lxc_seccomp_arch_all
;
714 ctx
.architectures
[0] = SCMP_ARCH_MIPSEL
;
715 ctx
.contexts
[0] = get_new_ctx(lxc_seccomp_arch_mipsel
,
716 default_policy_action
,
717 &ctx
.needs_merge
[0]);
718 if (!ctx
.contexts
[0])
721 ctx
.architectures
[1] = SCMP_ARCH_MIPSEL64N32
;
722 ctx
.contexts
[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32
,
723 default_policy_action
,
724 &ctx
.needs_merge
[1]);
725 if (!ctx
.contexts
[1])
728 ctx
.architectures
[2] = SCMP_ARCH_MIPSEL64
;
729 ctx
.contexts
[2] = get_new_ctx(lxc_seccomp_arch_mipsel64
,
730 default_policy_action
,
731 &ctx
.needs_merge
[2]);
732 if (!ctx
.contexts
[2])
737 if (default_policy_action
!= SCMP_ACT_KILL
) {
738 ret
= seccomp_reset(conf
->seccomp_ctx
, default_policy_action
);
740 ERROR("Error re-initializing Seccomp");
744 ret
= seccomp_attr_set(conf
->seccomp_ctx
, SCMP_FLTATR_CTL_NNP
, 0);
747 SYSERROR("Failed to turn off no-new-privs");
751 #ifdef SCMP_FLTATR_ATL_TSKIP
752 ret
= seccomp_attr_set(conf
->seccomp_ctx
, SCMP_FLTATR_ATL_TSKIP
, 1);
755 SYSWARN("Failed to turn on seccomp nop-skip, continuing");
760 while (getline(&line
, line_bufsz
, f
) != -1) {
767 remove_trailing_newlines(line
);
769 INFO("Processing \"%s\"", line
);
770 if (line
[0] == '[') {
771 /* Read the architecture for next set of rules. */
772 if (strcmp(line
, "[x86]") == 0 ||
773 strcmp(line
, "[X86]") == 0) {
774 if (native_arch
!= lxc_seccomp_arch_i386
&&
775 native_arch
!= lxc_seccomp_arch_amd64
) {
776 cur_rule_arch
= lxc_seccomp_arch_unknown
;
780 cur_rule_arch
= lxc_seccomp_arch_i386
;
781 } else if (strcmp(line
, "[x32]") == 0 ||
782 strcmp(line
, "[X32]") == 0) {
783 if (native_arch
!= lxc_seccomp_arch_amd64
) {
784 cur_rule_arch
= lxc_seccomp_arch_unknown
;
788 cur_rule_arch
= lxc_seccomp_arch_x32
;
789 } else if (strcmp(line
, "[X86_64]") == 0 ||
790 strcmp(line
, "[x86_64]") == 0) {
791 if (native_arch
!= lxc_seccomp_arch_amd64
) {
792 cur_rule_arch
= lxc_seccomp_arch_unknown
;
796 cur_rule_arch
= lxc_seccomp_arch_amd64
;
797 } else if (strcmp(line
, "[all]") == 0 ||
798 strcmp(line
, "[ALL]") == 0) {
799 cur_rule_arch
= lxc_seccomp_arch_all
;
802 else if (strcmp(line
, "[arm]") == 0 ||
803 strcmp(line
, "[ARM]") == 0) {
804 if (native_arch
!= lxc_seccomp_arch_arm
&&
805 native_arch
!= lxc_seccomp_arch_arm64
) {
806 cur_rule_arch
= lxc_seccomp_arch_unknown
;
810 cur_rule_arch
= lxc_seccomp_arch_arm
;
813 #ifdef SCMP_ARCH_AARCH64
814 else if (strcmp(line
, "[arm64]") == 0 ||
815 strcmp(line
, "[ARM64]") == 0) {
816 if (native_arch
!= lxc_seccomp_arch_arm64
) {
817 cur_rule_arch
= lxc_seccomp_arch_unknown
;
821 cur_rule_arch
= lxc_seccomp_arch_arm64
;
824 #ifdef SCMP_ARCH_PPC64LE
825 else if (strcmp(line
, "[ppc64le]") == 0 ||
826 strcmp(line
, "[PPC64LE]") == 0) {
827 if (native_arch
!= lxc_seccomp_arch_ppc64le
) {
828 cur_rule_arch
= lxc_seccomp_arch_unknown
;
832 cur_rule_arch
= lxc_seccomp_arch_ppc64le
;
835 #ifdef SCMP_ARCH_PPC64
836 else if (strcmp(line
, "[ppc64]") == 0 ||
837 strcmp(line
, "[PPC64]") == 0) {
838 if (native_arch
!= lxc_seccomp_arch_ppc64
) {
839 cur_rule_arch
= lxc_seccomp_arch_unknown
;
843 cur_rule_arch
= lxc_seccomp_arch_ppc64
;
847 else if (strcmp(line
, "[ppc]") == 0 ||
848 strcmp(line
, "[PPC]") == 0) {
849 if (native_arch
!= lxc_seccomp_arch_ppc
&&
850 native_arch
!= lxc_seccomp_arch_ppc64
) {
851 cur_rule_arch
= lxc_seccomp_arch_unknown
;
855 cur_rule_arch
= lxc_seccomp_arch_ppc
;
858 #ifdef SCMP_ARCH_MIPS
859 else if (strcmp(line
, "[mips64]") == 0 ||
860 strcmp(line
, "[MIPS64]") == 0) {
861 if (native_arch
!= lxc_seccomp_arch_mips64
) {
862 cur_rule_arch
= lxc_seccomp_arch_unknown
;
866 cur_rule_arch
= lxc_seccomp_arch_mips64
;
867 } else if (strcmp(line
, "[mips64n32]") == 0 ||
868 strcmp(line
, "[MIPS64N32]") == 0) {
869 if (native_arch
!= lxc_seccomp_arch_mips64
) {
870 cur_rule_arch
= lxc_seccomp_arch_unknown
;
874 cur_rule_arch
= lxc_seccomp_arch_mips64n32
;
875 } else if (strcmp(line
, "[mips]") == 0 ||
876 strcmp(line
, "[MIPS]") == 0) {
877 if (native_arch
!= lxc_seccomp_arch_mips
&&
878 native_arch
!= lxc_seccomp_arch_mips64
) {
879 cur_rule_arch
= lxc_seccomp_arch_unknown
;
883 cur_rule_arch
= lxc_seccomp_arch_mips
;
884 } else if (strcmp(line
, "[mipsel64]") == 0 ||
885 strcmp(line
, "[MIPSEL64]") == 0) {
886 if (native_arch
!= lxc_seccomp_arch_mipsel64
) {
887 cur_rule_arch
= lxc_seccomp_arch_unknown
;
891 cur_rule_arch
= lxc_seccomp_arch_mipsel64
;
892 } else if (strcmp(line
, "[mipsel64n32]") == 0 ||
893 strcmp(line
, "[MIPSEL64N32]") == 0) {
894 if (native_arch
!= lxc_seccomp_arch_mipsel64
) {
895 cur_rule_arch
= lxc_seccomp_arch_unknown
;
899 cur_rule_arch
= lxc_seccomp_arch_mipsel64n32
;
900 } else if (strcmp(line
, "[mipsel]") == 0 ||
901 strcmp(line
, "[MIPSEL]") == 0) {
902 if (native_arch
!= lxc_seccomp_arch_mipsel
&&
903 native_arch
!= lxc_seccomp_arch_mipsel64
) {
904 cur_rule_arch
= lxc_seccomp_arch_unknown
;
908 cur_rule_arch
= lxc_seccomp_arch_mipsel
;
911 #ifdef SCMP_ARCH_S390X
912 else if (strcmp(line
, "[s390x]") == 0 ||
913 strcmp(line
, "[S390X]") == 0) {
914 if (native_arch
!= lxc_seccomp_arch_s390x
) {
915 cur_rule_arch
= lxc_seccomp_arch_unknown
;
919 cur_rule_arch
= lxc_seccomp_arch_s390x
;
929 /* irrelevant arch - i.e. arm on i386 */
930 if (cur_rule_arch
== lxc_seccomp_arch_unknown
)
933 memset(&rule
, 0, sizeof(rule
));
934 /* read optional action which follows the syscall */
935 ret
= parse_v2_rules(line
, default_rule_action
, &rule
);
937 ERROR("Failed to interpret seccomp rule");
941 #if HAVE_DECL_SECCOMP_NOTIF_GET_FD
942 if ((rule
.action
== SCMP_ACT_USER_NOTIF
) &&
943 !conf
->has_seccomp_notify
) {
944 ret
= seccomp_attr_set(conf
->seccomp_ctx
,
945 SCMP_FLTATR_NEW_LISTENER
, 1);
949 conf
->has_seccomp_notify
= true;
950 TRACE("Set SCMP_FLTATR_NEW_LISTENER attribute");
954 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE
, line
,
955 conf
->seccomp_ctx
, &rule
))
958 INFO("Added native rule for arch %d for %s action %d(%s)",
959 SCMP_ARCH_NATIVE
, line
, rule
.action
,
960 get_action_name(rule
.action
));
962 if (ctx
.architectures
[0] != SCMP_ARCH_NATIVE
) {
963 if (!do_resolve_add_rule(ctx
.architectures
[0], line
,
964 ctx
.contexts
[0], &rule
))
967 INFO("Added compat rule for arch %d for %s action %d(%s)",
968 ctx
.architectures
[0], line
, rule
.action
,
969 get_action_name(rule
.action
));
972 if (ctx
.architectures
[1] != SCMP_ARCH_NATIVE
) {
973 if (!do_resolve_add_rule(ctx
.architectures
[1], line
,
974 ctx
.contexts
[1], &rule
))
977 INFO("Added compat rule for arch %d for %s action %d(%s)",
978 ctx
.architectures
[1], line
, rule
.action
,
979 get_action_name(rule
.action
));
982 if (ctx
.architectures
[2] != SCMP_ARCH_NATIVE
) {
983 if (!do_resolve_add_rule(ctx
.architectures
[2], line
,
984 ctx
.contexts
[2], &rule
))
987 INFO("Added native rule for arch %d for %s action %d(%s)",
988 ctx
.architectures
[2], line
, rule
.action
,
989 get_action_name(rule
.action
));
993 INFO("Merging compat seccomp contexts into main context");
994 if (ctx
.contexts
[0]) {
995 if (ctx
.needs_merge
[0]) {
996 ret
= seccomp_merge(conf
->seccomp_ctx
, ctx
.contexts
[0]);
998 ERROR("Failed to merge first compat seccomp "
999 "context into main context");
1003 TRACE("Merged first compat seccomp context into main context");
1005 seccomp_release(ctx
.contexts
[0]);
1006 ctx
.contexts
[0] = NULL
;
1010 if (ctx
.contexts
[1]) {
1011 if (ctx
.needs_merge
[1]) {
1012 ret
= seccomp_merge(conf
->seccomp_ctx
, ctx
.contexts
[1]);
1014 ERROR("Failed to merge first compat seccomp "
1015 "context into main context");
1019 TRACE("Merged second compat seccomp context into main context");
1021 seccomp_release(ctx
.contexts
[1]);
1022 ctx
.contexts
[1] = NULL
;
1026 if (ctx
.contexts
[2]) {
1027 if (ctx
.needs_merge
[2]) {
1028 ret
= seccomp_merge(conf
->seccomp_ctx
, ctx
.contexts
[2]);
1030 ERROR("Failed to merge third compat seccomp "
1031 "context into main context");
1035 TRACE("Merged third compat seccomp context into main context");
1037 seccomp_release(ctx
.contexts
[2]);
1038 ctx
.contexts
[2] = NULL
;
1046 ERROR("Unsupported architecture \"%s\"", line
);
1050 if (ctx
.contexts
[0])
1051 seccomp_release(ctx
.contexts
[0]);
1053 if (ctx
.contexts
[1])
1054 seccomp_release(ctx
.contexts
[1]);
1056 if (ctx
.contexts
[2])
1057 seccomp_release(ctx
.contexts
[2]);
1063 #else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
1064 static int parse_config_v2(FILE *f
, char *line
, struct lxc_conf
*conf
)
1068 #endif /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
1071 * The first line of the config file has a policy language version
1072 * the second line has some directives
1073 * then comes policy subject to the directives
1074 * right now version must be '1' or '2'
1075 * the directives must include 'whitelist'(version == 1 or 2) or 'blacklist'
1076 * (version == 2) and can include 'debug' (though debug is not yet supported).
1078 static int parse_config(FILE *f
, struct lxc_conf
*conf
)
1081 size_t line_bufsz
= 0;
1084 ret
= fscanf(f
, "%d\n", &version
);
1085 if (ret
!= 1 || (version
!= 1 && version
!= 2)) {
1086 ERROR("Invalid version");
1090 if (getline(&line
, &line_bufsz
, f
) == -1) {
1091 ERROR("Invalid config file");
1095 if (version
== 1 && !strstr(line
, "whitelist")) {
1096 ERROR("Only whitelist policy is supported");
1100 if (strstr(line
, "debug")) {
1101 ERROR("Debug not yet implemented");
1106 return parse_config_v1(f
, line
, &line_bufsz
, conf
);
1108 return parse_config_v2(f
, line
, &line_bufsz
, conf
);
1116 * use_seccomp: return true if we should try and apply a seccomp policy
1117 * if defined for the container.
1118 * This will return false if
1119 * 1. seccomp is not enabled in the kernel
1120 * 2. a seccomp policy is already enabled for this task
1122 static bool use_seccomp(const struct lxc_conf
*conf
)
1126 size_t line_bufsz
= 0;
1128 bool already_enabled
= false, found
= false;
1130 if (conf
->seccomp_allow_nesting
> 0)
1133 f
= fopen("/proc/self/status", "r");
1137 while (getline(&line
, &line_bufsz
, f
) != -1) {
1138 if (strncmp(line
, "Seccomp:", 8) == 0) {
1141 ret
= sscanf(line
+ 8, "%d", &v
);
1142 if (ret
== 1 && v
!= 0)
1143 already_enabled
= true;
1152 INFO("Seccomp is not enabled in the kernel");
1156 if (already_enabled
) {
1157 INFO("Already seccomp-confined, not loading new policy");
1164 int lxc_read_seccomp_config(struct lxc_conf
*conf
)
1172 if (!use_seccomp(conf
))
1175 #if HAVE_SCMP_FILTER_CTX
1176 /* XXX for debug, pass in SCMP_ACT_TRAP */
1177 conf
->seccomp_ctx
= seccomp_init(SCMP_ACT_KILL
);
1178 ret
= !conf
->seccomp_ctx
;
1180 ret
= seccomp_init(SCMP_ACT_KILL
) < 0;
1183 ERROR("Failed initializing seccomp");
1187 /* turn off no-new-privs. We don't want it in lxc, and it breaks
1189 #if HAVE_SCMP_FILTER_CTX
1190 ret
= seccomp_attr_set(conf
->seccomp_ctx
, SCMP_FLTATR_CTL_NNP
, 0);
1192 ret
= seccomp_attr_set(SCMP_FLTATR_CTL_NNP
, 0);
1196 SYSERROR("Failed to turn off no-new-privs");
1200 #ifdef SCMP_FLTATR_ATL_TSKIP
1201 ret
= seccomp_attr_set(conf
->seccomp_ctx
, SCMP_FLTATR_ATL_TSKIP
, 1);
1204 SYSWARN("Failed to turn on seccomp nop-skip, continuing");
1208 f
= fopen(conf
->seccomp
, "r");
1210 SYSERROR("Failed to open seccomp policy file %s", conf
->seccomp
);
1214 ret
= parse_config(f
, conf
);
1220 int lxc_seccomp_load(struct lxc_conf
*conf
)
1227 if (!use_seccomp(conf
))
1230 #if HAVE_SCMP_FILTER_CTX
1231 ret
= seccomp_load(conf
->seccomp_ctx
);
1233 ret
= seccomp_load();
1237 SYSERROR("Error loading the seccomp policy");
1241 /* After load seccomp filter into the kernel successfully, export the current seccomp
1242 * filter to log file */
1243 #if HAVE_SCMP_FILTER_CTX
1244 if ((lxc_log_get_level() <= LXC_LOG_LEVEL_TRACE
||
1245 conf
->loglevel
<= LXC_LOG_LEVEL_TRACE
) &&
1247 ret
= seccomp_export_pfc(conf
->seccomp_ctx
, lxc_log_fd
);
1248 /* Just give an warning when export error */
1251 SYSWARN("Failed to export seccomp filter to log file");
1256 #if HAVE_DECL_SECCOMP_NOTIF_GET_FD
1257 if (conf
->has_seccomp_notify
) {
1258 ret
= seccomp_notif_get_fd(conf
->seccomp_ctx
);
1264 conf
->seccomp_notify_fd
= ret
;
1265 TRACE("Retrieved new seccomp listener fd %d", ret
);
1272 void lxc_seccomp_free(struct lxc_conf
*conf
)
1274 free(conf
->seccomp
);
1275 conf
->seccomp
= NULL
;
1277 #if HAVE_SCMP_FILTER_CTX
1278 if (conf
->seccomp_ctx
) {
1279 seccomp_release(conf
->seccomp_ctx
);
1280 conf
->seccomp_ctx
= NULL
;
1284 #if HAVE_DECL_SECCOMP_NOTIF_GET_FD
1285 close_prot_errno_disarm(conf
->seccomp_notify_fd
);
1286 close_prot_errno_disarm(conf
->seccomp_notify_proxy_fd
);
1287 seccomp_notif_free(conf
->seccomp_notify_req
, conf
->seccomp_notify_resp
);
1288 conf
->seccomp_notify_req
= NULL
;
1289 conf
->seccomp_notify_resp
= NULL
;
1293 int seccomp_notify_handler(int fd
, uint32_t events
, void *data
,
1294 struct lxc_epoll_descr
*descr
)
1297 #if HAVE_DECL_SECCOMP_NOTIF_GET_FD
1299 struct lxc_handler
*hdlr
= data
;
1300 struct lxc_conf
*conf
= hdlr
->conf
;
1301 struct seccomp_notif
*req
= conf
->seccomp_notify_req
;
1302 struct seccomp_notif_resp
*resp
= conf
->seccomp_notify_resp
;
1303 int listener_proxy_fd
= conf
->seccomp_notify_proxy_fd
;
1304 struct seccomp_notify_proxy_msg msg
;
1306 if (listener_proxy_fd
< 0)
1307 return minus_one_set_errno(EINVAL
);
1309 ret
= seccomp_notif_receive(fd
, req
);
1311 return minus_one_set_errno(-ret
);
1313 memcpy(&msg
.req
, req
, sizeof(msg
.req
));
1314 msg
.monitor_pid
= hdlr
->monitor_pid
;
1315 msg
.init_pid
= hdlr
->pid
;
1317 ret
= lxc_send_nointr(listener_proxy_fd
, &msg
, sizeof(msg
), MSG_NOSIGNAL
);
1318 if (ret
< 0 || ret
!= (ssize_t
)sizeof(msg
))
1321 ret
= lxc_recv_nointr(listener_proxy_fd
, &msg
, sizeof(msg
), 0);
1322 if (ret
!= (ssize_t
)sizeof(msg
))
1325 memcpy(resp
, &msg
.resp
, sizeof(*resp
));
1327 ret
= seccomp_notif_send_resp(fd
, resp
);
1329 return minus_one_set_errno(-ret
);