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
30 #include <sys/utsname.h>
31 #include <sys/mount.h>
34 #include "lxcseccomp.h"
37 lxc_log_define(lxc_seccomp
, lxc
);
39 static int parse_config_v1(FILE *f
, struct lxc_conf
*conf
)
44 while (fgets(line
, 1024, f
)) {
46 ret
= sscanf(line
, "%d", &nr
);
49 ret
= seccomp_rule_add(
50 #if HAVE_SCMP_FILTER_CTX
53 SCMP_ACT_ALLOW
, nr
, 0);
55 ERROR("failed loading allow rule for %d", nr
);
62 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
63 static void remove_trailing_newlines(char *l
)
69 while (--p
>= l
&& *p
== '\n')
73 static uint32_t get_v2_default_action(char *line
)
75 uint32_t ret_action
= -1;
77 while (*line
== ' ') 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) {
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 uint32_t get_and_clear_v2_action(char *line
, uint32_t def_action
)
97 char *p
= strchr(line
, ' ');
106 if (!*p
|| *p
== '#')
108 ret
= get_v2_default_action(p
);
111 case -1: return def_action
;
117 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
118 enum lxc_hostarch_t
{
119 lxc_seccomp_arch_all
= 0,
120 lxc_seccomp_arch_native
,
121 lxc_seccomp_arch_i386
,
122 lxc_seccomp_arch_amd64
,
123 lxc_seccomp_arch_arm
,
124 lxc_seccomp_arch_unknown
= 999,
127 int get_hostarch(void)
130 if (uname(&uts
) < 0) {
131 SYSERROR("Failed to read host arch");
134 if (strcmp(uts
.machine
, "i686") == 0)
135 return lxc_seccomp_arch_i386
;
136 else if (strcmp(uts
.machine
, "x86_64") == 0)
137 return lxc_seccomp_arch_amd64
;
138 else if (strncmp(uts
.machine
, "armv7", 5) == 0)
139 return lxc_seccomp_arch_arm
;
140 return lxc_seccomp_arch_unknown
;
143 scmp_filter_ctx
get_new_ctx(enum lxc_hostarch_t n_arch
, uint32_t default_policy_action
)
150 case lxc_seccomp_arch_i386
: arch
= SCMP_ARCH_X86
; break;
151 case lxc_seccomp_arch_amd64
: arch
= SCMP_ARCH_X86_64
; break;
152 case lxc_seccomp_arch_arm
: arch
= SCMP_ARCH_ARM
; break;
153 default: return NULL
;
156 if ((ctx
= seccomp_init(default_policy_action
)) == NULL
) {
157 ERROR("Error initializing seccomp context");
160 if (seccomp_attr_set(ctx
, SCMP_FLTATR_CTL_NNP
, 0)) {
161 ERROR("failed to turn off n-new-privs");
162 seccomp_release(ctx
);
165 ret
= seccomp_arch_add(ctx
, arch
);
167 ERROR("Seccomp error %d (%s) adding arch: %d", ret
,
168 strerror(ret
), (int)n_arch
);
169 seccomp_release(ctx
);
172 if (seccomp_arch_remove(ctx
, SCMP_ARCH_NATIVE
) != 0) {
173 ERROR("Seccomp error removing native arch");
174 seccomp_release(ctx
);
181 bool do_resolve_add_rule(uint32_t arch
, char *line
, scmp_filter_ctx ctx
,
186 if (arch
&& seccomp_arch_exist(ctx
, arch
) != 0) {
187 ERROR("BUG: seccomp: rule and context arch do not match (arch %d)", arch
);
191 if (strncmp(line
, "reject_force_umount", 19) == 0) {
192 INFO("Setting seccomp rule to reject force umounts\n");
193 ret
= seccomp_rule_add_exact(ctx
, SCMP_ACT_ERRNO(EACCES
), SCMP_SYS(umount2
),
194 1, SCMP_A1(SCMP_CMP_MASKED_EQ
, MNT_FORCE
, MNT_FORCE
));
196 ERROR("failed (%d) loading rule to reject force umount", ret
);
202 nr
= seccomp_syscall_resolve_name(line
);
203 if (nr
== __NR_SCMP_ERROR
) {
204 WARN("Seccomp: failed to resolve syscall: %s", line
);
205 WARN("This syscall will NOT be blacklisted");
209 WARN("Seccomp: got negative # for syscall: %s", line
);
210 WARN("This syscall will NOT be blacklisted");
213 ret
= seccomp_rule_add_exact(ctx
, action
, nr
, 0);
215 ERROR("failed (%d) loading rule for %s (nr %d action %d)", ret
, line
, nr
, action
);
235 static int parse_config_v2(FILE *f
, char *line
, struct lxc_conf
*conf
)
239 scmp_filter_ctx compat_ctx
= NULL
;
240 bool blacklist
= false;
241 uint32_t default_policy_action
= -1, default_rule_action
= -1, action
;
242 enum lxc_hostarch_t native_arch
= get_hostarch(),
243 cur_rule_arch
= native_arch
;
245 if (strncmp(line
, "blacklist", 9) == 0)
247 else if (strncmp(line
, "whitelist", 9) != 0) {
248 ERROR("Bad seccomp policy style: %s", line
);
252 if ((p
= strchr(line
, ' '))) {
253 default_policy_action
= get_v2_default_action(p
+1);
254 if (default_policy_action
== -2)
258 /* for blacklist, allow any syscall which has no rule */
260 if (default_policy_action
== -1)
261 default_policy_action
= SCMP_ACT_ALLOW
;
262 if (default_rule_action
== -1)
263 default_rule_action
= SCMP_ACT_KILL
;
265 if (default_policy_action
== -1)
266 default_policy_action
= SCMP_ACT_KILL
;
267 if (default_rule_action
== -1)
268 default_rule_action
= SCMP_ACT_ALLOW
;
271 if (native_arch
== lxc_seccomp_arch_amd64
) {
272 cur_rule_arch
= lxc_seccomp_arch_all
;
273 compat_ctx
= get_new_ctx(lxc_seccomp_arch_i386
,
274 default_policy_action
);
279 if (default_policy_action
!= SCMP_ACT_KILL
) {
280 ret
= seccomp_reset(conf
->seccomp_ctx
, default_policy_action
);
282 ERROR("Error re-initializing seccomp");
285 if (seccomp_attr_set(conf
->seccomp_ctx
, SCMP_FLTATR_CTL_NNP
, 0)) {
286 ERROR("failed to turn off n-new-privs");
291 while (fgets(line
, 1024, f
)) {
295 if (strlen(line
) == 0)
297 remove_trailing_newlines(line
);
298 INFO("processing: .%s.", line
);
299 if (line
[0] == '[') {
300 // read the architecture for next set of rules
301 if (strcmp(line
, "[x86]") == 0 ||
302 strcmp(line
, "[X86]") == 0) {
303 if (native_arch
!= lxc_seccomp_arch_i386
&&
304 native_arch
!= lxc_seccomp_arch_amd64
) {
305 cur_rule_arch
= lxc_seccomp_arch_unknown
;
308 cur_rule_arch
= lxc_seccomp_arch_i386
;
309 if (native_arch
== lxc_seccomp_arch_amd64
) {
312 compat_ctx
= get_new_ctx(lxc_seccomp_arch_i386
,
313 default_policy_action
);
317 } else if (strcmp(line
, "[X86_64]") == 0 ||
318 strcmp(line
, "[x86_64]") == 0) {
319 if (native_arch
!= lxc_seccomp_arch_amd64
) {
320 cur_rule_arch
= lxc_seccomp_arch_unknown
;
323 cur_rule_arch
= lxc_seccomp_arch_amd64
;
324 } else if (strcmp(line
, "[all]") == 0 ||
325 strcmp(line
, "[ALL]") == 0) {
326 cur_rule_arch
= lxc_seccomp_arch_all
;
327 if (native_arch
== lxc_seccomp_arch_amd64
&& !compat_ctx
) {
330 compat_ctx
= get_new_ctx(lxc_seccomp_arch_i386
,
331 default_policy_action
);
337 else if (strcmp(line
, "[arm]") == 0 ||
338 strcmp(line
, "[ARM]") == 0) {
339 if (native_arch
!= lxc_seccomp_arch_arm
) {
340 cur_rule_arch
= lxc_seccomp_arch_unknown
;
343 cur_rule_arch
= lxc_seccomp_arch_arm
;
352 /* irrelevant arch - i.e. arm on i386 */
353 if (cur_rule_arch
== lxc_seccomp_arch_unknown
)
356 /* read optional action which follows the syscall */
357 action
= get_and_clear_v2_action(line
, default_rule_action
);
359 ERROR("Failed to interpret action");
364 * TODO generalize - if !is_compat_only(native_arch, cur_rule_arch)
366 * in other words, the rule is 32-bit only, on 64-bit host; don't run
367 * the rule against the native arch.
369 if (!(cur_rule_arch
== lxc_seccomp_arch_i386
&&
370 native_arch
== lxc_seccomp_arch_amd64
)) {
371 INFO("Adding non-compat rule for %s action %d", line
, action
);
372 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE
, line
, conf
->seccomp_ctx
, action
))
377 * TODO generalize - if need_compat(native_arch, cur_rule_arch)
379 if (native_arch
== lxc_seccomp_arch_amd64
&&
380 cur_rule_arch
!= lxc_seccomp_arch_amd64
) {
382 INFO("Adding compat rule for %s action %d", line
, action
);
383 nr1
= seccomp_syscall_resolve_name_arch(SCMP_ARCH_X86
, line
);
384 nr2
= seccomp_syscall_resolve_name_arch(SCMP_ARCH_NATIVE
, line
);
386 /* If the syscall # is the same for 32- and 64-bit, then we cannot
387 * apply it to the compat_ctx. So apply it to the noncompat ctx.
388 * We may already have done so, but that's ok
390 INFO("Adding non-compat rule bc nr1 == nr2 (%d, %d)", nr1
, nr2
);
391 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE
, line
, conf
->seccomp_ctx
, action
))
395 INFO("Really adding compat rule bc nr1 == nr2 (%d, %d)", nr1
, nr2
);
396 if (!do_resolve_add_rule(SCMP_ARCH_X86
, line
,
403 INFO("Merging in the compat seccomp ctx into the main one");
404 if (seccomp_merge(conf
->seccomp_ctx
, compat_ctx
) != 0) {
405 ERROR("Error merging i386 seccomp contexts");
413 ERROR("Unsupported arch: %s", line
);
417 seccomp_release(compat_ctx
);
420 #else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
421 static int parse_config_v2(FILE *f
, char *line
, struct lxc_conf
*conf
)
425 #endif /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
428 * The first line of the config file has a policy language version
429 * the second line has some directives
430 * then comes policy subject to the directives
431 * right now version must be '1'
432 * the directives must include 'whitelist' (only type of policy currently
433 * supported) and can include 'debug' (though debug is not yet supported).
435 static int parse_config(FILE *f
, struct lxc_conf
*conf
)
440 ret
= fscanf(f
, "%d\n", &version
);
441 if (ret
!= 1 || (version
!= 1 && version
!= 2)) {
442 ERROR("invalid version");
445 if (!fgets(line
, 1024, f
)) {
446 ERROR("invalid config file");
449 if (version
== 1 && !strstr(line
, "whitelist")) {
450 ERROR("only whitelist policy is supported");
454 if (strstr(line
, "debug")) {
455 ERROR("debug not yet implemented");
460 return parse_config_v1(f
, conf
);
461 return parse_config_v2(f
, line
, conf
);
465 * use_seccomp: return true if we should try and apply a seccomp policy
466 * if defined for the container.
467 * This will return false if
468 * 1. seccomp is not enabled in the kernel
469 * 2. a seccomp policy is already enabled for this task
471 static bool use_seccomp(void)
473 FILE *f
= fopen("/proc/self/status", "r");
475 bool already_enabled
= false;
482 while (fgets(line
, 1024, f
)) {
483 if (strncmp(line
, "Seccomp:", 8) == 0) {
485 ret
= sscanf(line
+8, "%d", &v
);
486 if (ret
== 1 && v
!= 0)
487 already_enabled
= true;
493 if (!found
) { /* no Seccomp line, no seccomp in kernel */
494 INFO("Seccomp is not enabled in the kernel");
497 if (already_enabled
) { /* already seccomp-confined */
498 INFO("Already seccomp-confined, not loading new policy");
504 int lxc_read_seccomp_config(struct lxc_conf
*conf
)
514 #if HAVE_SCMP_FILTER_CTX
515 /* XXX for debug, pass in SCMP_ACT_TRAP */
516 conf
->seccomp_ctx
= seccomp_init(SCMP_ACT_KILL
);
517 ret
= !conf
->seccomp_ctx
;
519 ret
= seccomp_init(SCMP_ACT_KILL
) < 0;
522 ERROR("failed initializing seccomp");
526 /* turn of no-new-privs. We don't want it in lxc, and it breaks
528 if (seccomp_attr_set(
529 #if HAVE_SCMP_FILTER_CTX
532 SCMP_FLTATR_CTL_NNP
, 0)) {
533 ERROR("failed to turn off n-new-privs");
537 f
= fopen(conf
->seccomp
, "r");
539 SYSERROR("failed to open seccomp policy file %s", conf
->seccomp
);
542 ret
= parse_config(f
, conf
);
547 int lxc_seccomp_load(struct lxc_conf
*conf
)
555 #if HAVE_SCMP_FILTER_CTX
560 ERROR("Error loading the seccomp policy");
566 void lxc_seccomp_free(struct lxc_conf
*conf
) {
568 conf
->seccomp
= NULL
;
569 #if HAVE_SCMP_FILTER_CTX
570 if (conf
->seccomp_ctx
) {
571 seccomp_release(conf
->seccomp_ctx
);
572 conf
->seccomp_ctx
= NULL
;