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>
33 #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;
76 while (*line
== ' ') line
++;
77 // after 'whitelist' or 'blacklist' comes default behavior
78 if (strncmp(line
, "kill", 4) == 0)
79 ret_action
= SCMP_ACT_KILL
;
80 else if (strncmp(line
, "errno", 5) == 0) {
82 if (sscanf(line
+5, "%d", &e
) != 1) {
83 ERROR("Bad errno value in %s", line
);
86 ret_action
= SCMP_ACT_ERRNO(e
);
87 } else if (strncmp(line
, "allow", 5) == 0)
88 ret_action
= SCMP_ACT_ALLOW
;
89 else if (strncmp(line
, "trap", 4) == 0)
90 ret_action
= SCMP_ACT_TRAP
;
94 static uint32_t get_and_clear_v2_action(char *line
, uint32_t def_action
)
96 char *p
= strchr(line
, ' ');
105 if (!*p
|| *p
== '#')
107 ret
= get_v2_default_action(p
);
110 case -1: return def_action
;
116 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
117 enum lxc_hostarch_t
{
118 lxc_seccomp_arch_all
= 0,
119 lxc_seccomp_arch_native
,
120 lxc_seccomp_arch_i386
,
121 lxc_seccomp_arch_amd64
,
122 lxc_seccomp_arch_arm
,
123 lxc_seccomp_arch_unknown
= 999,
126 int get_hostarch(void)
129 if (uname(&uts
) < 0) {
130 SYSERROR("Failed to read host arch");
133 if (strcmp(uts
.machine
, "i686") == 0)
134 return lxc_seccomp_arch_i386
;
135 else if (strcmp(uts
.machine
, "x86_64") == 0)
136 return lxc_seccomp_arch_amd64
;
137 else if (strncmp(uts
.machine
, "armv7", 5) == 0)
138 return lxc_seccomp_arch_arm
;
139 return lxc_seccomp_arch_unknown
;
142 scmp_filter_ctx
get_new_ctx(enum lxc_hostarch_t n_arch
, uint32_t default_policy_action
)
149 case lxc_seccomp_arch_i386
: arch
= SCMP_ARCH_X86
; break;
150 case lxc_seccomp_arch_amd64
: arch
= SCMP_ARCH_X86_64
; break;
151 case lxc_seccomp_arch_arm
: arch
= SCMP_ARCH_ARM
; break;
152 default: return NULL
;
155 if ((ctx
= seccomp_init(default_policy_action
)) == NULL
) {
156 ERROR("Error initializing seccomp context");
159 if (seccomp_attr_set(ctx
, SCMP_FLTATR_CTL_NNP
, 0)) {
160 ERROR("failed to turn off n-new-privs");
161 seccomp_release(ctx
);
164 ret
= seccomp_arch_add(ctx
, arch
);
166 ERROR("Seccomp error %d (%s) adding arch: %d", ret
,
167 strerror(ret
), (int)n_arch
);
168 seccomp_release(ctx
);
171 if (seccomp_arch_remove(ctx
, SCMP_ARCH_NATIVE
) != 0) {
172 ERROR("Seccomp error removing native arch");
173 seccomp_release(ctx
);
180 bool do_resolve_add_rule(uint32_t arch
, char *line
, scmp_filter_ctx ctx
,
185 if (arch
&& seccomp_arch_exist(ctx
, arch
) != 0) {
186 ERROR("BUG: seccomp: rule and context arch do not match (arch %d)", arch
);
189 nr
= seccomp_syscall_resolve_name(line
);
190 if (nr
== __NR_SCMP_ERROR
) {
191 WARN("Seccomp: failed to resolve syscall: %s", line
);
192 WARN("This syscall will NOT be blacklisted");
196 WARN("Seccomp: got negative # for syscall: %s", line
);
197 WARN("This syscall will NOT be blacklisted");
200 ret
= seccomp_rule_add_exact(ctx
, action
, nr
, 0);
202 ERROR("failed (%d) loading rule for %s (nr %d action %d)", ret
, line
, nr
, action
);
222 static int parse_config_v2(FILE *f
, char *line
, struct lxc_conf
*conf
)
226 scmp_filter_ctx compat_ctx
= NULL
;
227 bool blacklist
= false;
228 uint32_t default_policy_action
= -1, default_rule_action
= -1, action
;
229 enum lxc_hostarch_t native_arch
= get_hostarch(),
230 cur_rule_arch
= native_arch
;
232 if (strncmp(line
, "blacklist", 9) == 0)
234 else if (strncmp(line
, "whitelist", 9) != 0) {
235 ERROR("Bad seccomp policy style: %s", line
);
239 if ((p
= strchr(line
, ' '))) {
240 default_policy_action
= get_v2_default_action(p
+1);
241 if (default_policy_action
== -2)
245 /* for blacklist, allow any syscall which has no rule */
247 if (default_policy_action
== -1)
248 default_policy_action
= SCMP_ACT_ALLOW
;
249 if (default_rule_action
== -1)
250 default_rule_action
= SCMP_ACT_KILL
;
252 if (default_policy_action
== -1)
253 default_policy_action
= SCMP_ACT_KILL
;
254 if (default_rule_action
== -1)
255 default_rule_action
= SCMP_ACT_ALLOW
;
258 if (native_arch
== lxc_seccomp_arch_amd64
) {
259 cur_rule_arch
= lxc_seccomp_arch_all
;
260 compat_ctx
= get_new_ctx(lxc_seccomp_arch_i386
,
261 default_policy_action
);
266 if (default_policy_action
!= SCMP_ACT_KILL
) {
267 ret
= seccomp_reset(conf
->seccomp_ctx
, default_policy_action
);
269 ERROR("Error re-initializing seccomp");
272 if (seccomp_attr_set(conf
->seccomp_ctx
, SCMP_FLTATR_CTL_NNP
, 0)) {
273 ERROR("failed to turn off n-new-privs");
278 while (fgets(line
, 1024, f
)) {
282 if (strlen(line
) == 0)
284 remove_trailing_newlines(line
);
285 INFO("processing: .%s.", line
);
286 if (line
[0] == '[') {
287 // read the architecture for next set of rules
288 if (strcmp(line
, "[x86]") == 0 ||
289 strcmp(line
, "[X86]") == 0) {
290 if (native_arch
!= lxc_seccomp_arch_i386
&&
291 native_arch
!= lxc_seccomp_arch_amd64
) {
292 cur_rule_arch
= lxc_seccomp_arch_unknown
;
295 cur_rule_arch
= lxc_seccomp_arch_i386
;
296 if (native_arch
== lxc_seccomp_arch_amd64
) {
299 compat_ctx
= get_new_ctx(lxc_seccomp_arch_i386
,
300 default_policy_action
);
304 } else if (strcmp(line
, "[X86_64]") == 0 ||
305 strcmp(line
, "[x86_64]") == 0) {
306 if (native_arch
!= lxc_seccomp_arch_amd64
) {
307 cur_rule_arch
= lxc_seccomp_arch_unknown
;
310 cur_rule_arch
= lxc_seccomp_arch_amd64
;
311 } else if (strcmp(line
, "[all]") == 0 ||
312 strcmp(line
, "[ALL]") == 0) {
313 cur_rule_arch
= lxc_seccomp_arch_all
;
314 if (native_arch
== lxc_seccomp_arch_amd64
&& !compat_ctx
) {
317 compat_ctx
= get_new_ctx(lxc_seccomp_arch_i386
,
318 default_policy_action
);
324 else if (strcmp(line
, "[arm]") == 0 ||
325 strcmp(line
, "[ARM]") == 0) {
326 if (native_arch
!= lxc_seccomp_arch_arm
) {
327 cur_rule_arch
= lxc_seccomp_arch_unknown
;
330 cur_rule_arch
= lxc_seccomp_arch_arm
;
339 /* irrelevant arch - i.e. arm on i386 */
340 if (cur_rule_arch
== lxc_seccomp_arch_unknown
)
343 /* read optional action which follows the syscall */
344 action
= get_and_clear_v2_action(line
, default_rule_action
);
346 ERROR("Failed to interpret action");
351 * TODO generalize - if !is_compat_only(native_arch, cur_rule_arch)
353 * in other words, the rule is 32-bit only, on 64-bit host; don't run
354 * the rule against the native arch.
356 if (!(cur_rule_arch
== lxc_seccomp_arch_i386
&&
357 native_arch
== lxc_seccomp_arch_amd64
)) {
358 INFO("Adding non-compat rule for %s action %d", line
, action
);
359 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE
, line
, conf
->seccomp_ctx
, action
))
364 * TODO generalize - if need_compat(native_arch, cur_rule_arch)
366 if (native_arch
== lxc_seccomp_arch_amd64
&&
367 cur_rule_arch
!= lxc_seccomp_arch_amd64
) {
369 INFO("Adding compat rule for %s action %d", line
, action
);
370 nr1
= seccomp_syscall_resolve_name_arch(SCMP_ARCH_X86
, line
);
371 nr2
= seccomp_syscall_resolve_name_arch(SCMP_ARCH_NATIVE
, line
);
373 /* If the syscall # is the same for 32- and 64-bit, then we cannot
374 * apply it to the compat_ctx. So apply it to the noncompat ctx.
375 * We may already have done so, but that's ok
377 INFO("Adding non-compat rule bc nr1 == nr2 (%d, %d)", nr1
, nr2
);
378 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE
, line
, conf
->seccomp_ctx
, action
))
382 INFO("Really adding compat rule bc nr1 == nr2 (%d, %d)", nr1
, nr2
);
383 if (!do_resolve_add_rule(SCMP_ARCH_X86
, line
,
390 INFO("Merging in the compat seccomp ctx into the main one");
391 if (seccomp_merge(conf
->seccomp_ctx
, compat_ctx
) != 0) {
392 ERROR("Error merging i386 seccomp contexts");
399 ERROR("Unsupported arch: %s", line
);
403 seccomp_release(compat_ctx
);
406 #else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
407 static int parse_config_v2(FILE *f
, char *line
, struct lxc_conf
*conf
)
411 #endif /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
414 * The first line of the config file has a policy language version
415 * the second line has some directives
416 * then comes policy subject to the directives
417 * right now version must be '1'
418 * the directives must include 'whitelist' (only type of policy currently
419 * supported) and can include 'debug' (though debug is not yet supported).
421 static int parse_config(FILE *f
, struct lxc_conf
*conf
)
426 ret
= fscanf(f
, "%d\n", &version
);
427 if (ret
!= 1 || (version
!= 1 && version
!= 2)) {
428 ERROR("invalid version");
431 if (!fgets(line
, 1024, f
)) {
432 ERROR("invalid config file");
435 if (version
== 1 && !strstr(line
, "whitelist")) {
436 ERROR("only whitelist policy is supported");
440 if (strstr(line
, "debug")) {
441 ERROR("debug not yet implemented");
446 return parse_config_v1(f
, conf
);
447 return parse_config_v2(f
, line
, conf
);
451 * use_seccomp: return true if we should try and apply a seccomp policy
452 * if defined for the container.
453 * This will return false if
454 * 1. seccomp is not enabled in the kernel
455 * 2. a seccomp policy is already enabled for this task
457 static bool use_seccomp(void)
459 FILE *f
= fopen("/proc/self/status", "r");
461 bool already_enabled
= false;
468 while (fgets(line
, 1024, f
)) {
469 if (strncmp(line
, "Seccomp:", 8) == 0) {
471 ret
= sscanf(line
+8, "%d", &v
);
472 if (ret
== 1 && v
!= 0)
473 already_enabled
= true;
479 if (!found
) { /* no Seccomp line, no seccomp in kernel */
480 INFO("Seccomp is not enabled in the kernel");
483 if (already_enabled
) { /* already seccomp-confined */
484 INFO("Already seccomp-confined, not loading new policy");
490 int lxc_read_seccomp_config(struct lxc_conf
*conf
)
500 #if HAVE_SCMP_FILTER_CTX
501 /* XXX for debug, pass in SCMP_ACT_TRAP */
502 conf
->seccomp_ctx
= seccomp_init(SCMP_ACT_KILL
);
503 ret
= !conf
->seccomp_ctx
;
505 ret
= seccomp_init(SCMP_ACT_KILL
) < 0;
508 ERROR("failed initializing seccomp");
512 /* turn of no-new-privs. We don't want it in lxc, and it breaks
514 if (seccomp_attr_set(
515 #if HAVE_SCMP_FILTER_CTX
518 SCMP_FLTATR_CTL_NNP
, 0)) {
519 ERROR("failed to turn off n-new-privs");
523 f
= fopen(conf
->seccomp
, "r");
525 SYSERROR("failed to open seccomp policy file %s", conf
->seccomp
);
528 ret
= parse_config(f
, conf
);
533 int lxc_seccomp_load(struct lxc_conf
*conf
)
541 #if HAVE_SCMP_FILTER_CTX
546 ERROR("Error loading the seccomp policy");
552 void lxc_seccomp_free(struct lxc_conf
*conf
) {
555 conf
->seccomp
= NULL
;
557 #if HAVE_SCMP_FILTER_CTX
558 if (conf
->seccomp_ctx
) {
559 seccomp_release(conf
->seccomp_ctx
);
560 conf
->seccomp_ctx
= NULL
;