/* * v2 consists of * [x86] * open * read * write * close * # a comment * [x86_64] * open * read * write * close */ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf) { char *p; int ret; scmp_filter_ctx compat_ctx[2] = {NULL, NULL}; bool blacklist = false; uint32_t default_policy_action = -1, default_rule_action = -1, action; enum lxc_hostarch_t native_arch = get_hostarch(), cur_rule_arch = native_arch; uint32_t compat_arch[2] = {SCMP_ARCH_NATIVE, SCMP_ARCH_NATIVE}; if (strncmp(line, "blacklist", 9) == 0) blacklist = true; else if (strncmp(line, "whitelist", 9) != 0) { ERROR("Bad seccomp policy style: %s.", line); return -1; } if ((p = strchr(line, ' '))) { default_policy_action = get_v2_default_action(p + 1); if (default_policy_action == -2) return -1; } /* for blacklist, allow any syscall which has no rule */ if (blacklist) { if (default_policy_action == -1) default_policy_action = SCMP_ACT_ALLOW; if (default_rule_action == -1) default_rule_action = SCMP_ACT_KILL; } else { if (default_policy_action == -1) default_policy_action = SCMP_ACT_KILL; if (default_rule_action == -1) default_rule_action = SCMP_ACT_ALLOW; } if (native_arch == lxc_seccomp_arch_amd64) { cur_rule_arch = lxc_seccomp_arch_all; compat_arch[0] = SCMP_ARCH_X86; compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_i386, default_policy_action); compat_arch[1] = SCMP_ARCH_X32; compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_x32, default_policy_action); if (!compat_ctx[0] || !compat_ctx[1]) goto bad; #ifdef SCMP_ARCH_PPC } else if (native_arch == lxc_seccomp_arch_ppc64) { cur_rule_arch = lxc_seccomp_arch_all; compat_arch[0] = SCMP_ARCH_PPC; compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_ppc, default_policy_action); if (!compat_ctx[0]) goto bad; #endif #ifdef SCMP_ARCH_ARM } else if (native_arch == lxc_seccomp_arch_arm64) { cur_rule_arch = lxc_seccomp_arch_all; compat_arch[0] = SCMP_ARCH_ARM; compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_arm, default_policy_action); if (!compat_ctx[0]) goto bad; #endif #ifdef SCMP_ARCH_MIPS } else if (native_arch == lxc_seccomp_arch_mips64) { cur_rule_arch = lxc_seccomp_arch_all; compat_arch[0] = SCMP_ARCH_MIPS; compat_arch[1] = SCMP_ARCH_MIPS64N32; compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mips, default_policy_action); compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mips64n32, default_policy_action); if (!compat_ctx[0] || !compat_ctx[1]) goto bad; } else if (native_arch == lxc_seccomp_arch_mipsel64) { cur_rule_arch = lxc_seccomp_arch_all; compat_arch[0] = SCMP_ARCH_MIPSEL; compat_arch[1] = SCMP_ARCH_MIPSEL64N32; compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mipsel, default_policy_action); compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32, default_policy_action); if (!compat_ctx[0] || !compat_ctx[1]) goto bad; #endif } if (default_policy_action != SCMP_ACT_KILL) { ret = seccomp_reset(conf->seccomp_ctx, default_policy_action); if (ret != 0) { ERROR("Error re-initializing Seccomp."); return -1; } if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) { ERROR("Failed to turn off n-new-privs."); return -1; } #ifdef SCMP_FLTATR_ATL_TSKIP if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) { WARN("Failed to turn on seccomp nop-skip, continuing"); } #endif } while (fgets(line, 1024, f)) { if (line[0] == '#') continue; if (strlen(line) == 0) continue; remove_trailing_newlines(line); INFO("processing: .%s.", line); if (line[0] == '[') { // read the architecture for next set of rules if (strcmp(line, "[x86]") == 0 || strcmp(line, "[X86]") == 0) { if (native_arch != lxc_seccomp_arch_i386 && native_arch != lxc_seccomp_arch_amd64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_i386; } else if (strcmp(line, "[x32]") == 0 || strcmp(line, "[X32]") == 0) { if (native_arch != lxc_seccomp_arch_amd64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_x32; } else if (strcmp(line, "[X86_64]") == 0 || strcmp(line, "[x86_64]") == 0) { if (native_arch != lxc_seccomp_arch_amd64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_amd64; } else if (strcmp(line, "[all]") == 0 || strcmp(line, "[ALL]") == 0) { cur_rule_arch = lxc_seccomp_arch_all; } #ifdef SCMP_ARCH_ARM else if (strcmp(line, "[arm]") == 0 || strcmp(line, "[ARM]") == 0) { if (native_arch != lxc_seccomp_arch_arm && native_arch != lxc_seccomp_arch_arm64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_arm; } #endif #ifdef SCMP_ARCH_AARCH64 else if (strcmp(line, "[arm64]") == 0 || strcmp(line, "[ARM64]") == 0) { if (native_arch != lxc_seccomp_arch_arm64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_arm64; } #endif #ifdef SCMP_ARCH_PPC64LE else if (strcmp(line, "[ppc64le]") == 0 || strcmp(line, "[PPC64LE]") == 0) { if (native_arch != lxc_seccomp_arch_ppc64le) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_ppc64le; } #endif #ifdef SCMP_ARCH_PPC64 else if (strcmp(line, "[ppc64]") == 0 || strcmp(line, "[PPC64]") == 0) { if (native_arch != lxc_seccomp_arch_ppc64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_ppc64; } #endif #ifdef SCMP_ARCH_PPC else if (strcmp(line, "[ppc]") == 0 || strcmp(line, "[PPC]") == 0) { if (native_arch != lxc_seccomp_arch_ppc && native_arch != lxc_seccomp_arch_ppc64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_ppc; } #endif #ifdef SCMP_ARCH_MIPS else if (strcmp(line, "[mips64]") == 0 || strcmp(line, "[MIPS64]") == 0) { if (native_arch != lxc_seccomp_arch_mips64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_mips64; } else if (strcmp(line, "[mips64n32]") == 0 || strcmp(line, "[MIPS64N32]") == 0) { if (native_arch != lxc_seccomp_arch_mips64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_mips64n32; } else if (strcmp(line, "[mips]") == 0 || strcmp(line, "[MIPS]") == 0) { if (native_arch != lxc_seccomp_arch_mips && native_arch != lxc_seccomp_arch_mips64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_mips; } else if (strcmp(line, "[mipsel64]") == 0 || strcmp(line, "[MIPSEL64]") == 0) { if (native_arch != lxc_seccomp_arch_mipsel64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_mipsel64; } else if (strcmp(line, "[mipsel64n32]") == 0 || strcmp(line, "[MIPSEL64N32]") == 0) { if (native_arch != lxc_seccomp_arch_mipsel64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_mipsel64n32; } else if (strcmp(line, "[mipsel]") == 0 || strcmp(line, "[MIPSEL]") == 0) { if (native_arch != lxc_seccomp_arch_mipsel && native_arch != lxc_seccomp_arch_mipsel64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_mipsel; } #endif #ifdef SCMP_ARCH_S390X else if (strcmp(line, "[s390x]") == 0 || strcmp(line, "[S390X]") == 0) { if (native_arch != lxc_seccomp_arch_s390x) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_s390x; } #endif else goto bad_arch; continue; } /* irrelevant arch - i.e. arm on i386 */ if (cur_rule_arch == lxc_seccomp_arch_unknown) continue; /* read optional action which follows the syscall */ action = get_and_clear_v2_action(line, default_rule_action); if (action == -1) { ERROR("Failed to interpret action."); goto bad_rule; } if (cur_rule_arch == native_arch || cur_rule_arch == lxc_seccomp_arch_native || compat_arch[0] == SCMP_ARCH_NATIVE) { INFO("Adding native rule for %s action %d.", line, action); if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action)) goto bad_rule; } else if (cur_rule_arch != lxc_seccomp_arch_all) { int arch_index = cur_rule_arch == lxc_seccomp_arch_mips64n32 || cur_rule_arch == lxc_seccomp_arch_mipsel64n32 ? 1 : 0; INFO("Adding compat-only rule for %s action %d.", line, action); if (!do_resolve_add_rule(compat_arch[arch_index], line, compat_ctx[arch_index], action)) goto bad_rule; } else { INFO("Adding native rule for %s action %d.", line, action); if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action)) goto bad_rule; INFO("Adding compat rule for %s action %d.", line, action); if (!do_resolve_add_rule(compat_arch[0], line, compat_ctx[0], action)) goto bad_rule; if (compat_arch[1] != SCMP_ARCH_NATIVE && !do_resolve_add_rule(compat_arch[1], line, compat_ctx[1], action)) goto bad_rule; } } if (compat_ctx[0]) { INFO("Merging in the compat Seccomp ctx into the main one."); if (seccomp_merge(conf->seccomp_ctx, compat_ctx[0]) != 0 || (compat_ctx[1] != NULL && seccomp_merge(conf->seccomp_ctx, compat_ctx[1]) != 0)) { ERROR("Error merging compat Seccomp contexts."); goto bad; } } return 0; bad_arch: ERROR("Unsupported arch: %s.", line); bad_rule: bad: if (compat_ctx[0]) seccomp_release(compat_ctx[0]); if (compat_ctx[1]) seccomp_release(compat_ctx[1]); return -1; }
/* * v2 consists of * [x86] * open * read * write * close * # a comment * [x86_64] * open * read * write * close */ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf) { char *p; int ret; scmp_filter_ctx compat_ctx = NULL; bool blacklist = false; uint32_t default_policy_action = -1, default_rule_action = -1, action; enum lxc_hostarch_t native_arch = get_hostarch(), cur_rule_arch = native_arch; if (strncmp(line, "blacklist", 9) == 0) blacklist = true; else if (strncmp(line, "whitelist", 9) != 0) { ERROR("Bad seccomp policy style: %s", line); return -1; } if ((p = strchr(line, ' '))) { default_policy_action = get_v2_default_action(p+1); if (default_policy_action == -2) return -1; } /* for blacklist, allow any syscall which has no rule */ if (blacklist) { if (default_policy_action == -1) default_policy_action = SCMP_ACT_ALLOW; if (default_rule_action == -1) default_rule_action = SCMP_ACT_KILL; } else { if (default_policy_action == -1) default_policy_action = SCMP_ACT_KILL; if (default_rule_action == -1) default_rule_action = SCMP_ACT_ALLOW; } if (native_arch == lxc_seccomp_arch_amd64) { cur_rule_arch = lxc_seccomp_arch_all; compat_ctx = get_new_ctx(lxc_seccomp_arch_i386, default_policy_action); if (!compat_ctx) goto bad; } if (default_policy_action != SCMP_ACT_KILL) { ret = seccomp_reset(conf->seccomp_ctx, default_policy_action); if (ret != 0) { ERROR("Error re-initializing seccomp"); return -1; } if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) { ERROR("failed to turn off n-new-privs"); return -1; } } while (fgets(line, 1024, f)) { if (line[0] == '#') continue; if (strlen(line) == 0) continue; remove_trailing_newlines(line); INFO("processing: .%s.", line); if (line[0] == '[') { // read the architecture for next set of rules if (strcmp(line, "[x86]") == 0 || strcmp(line, "[X86]") == 0) { if (native_arch != lxc_seccomp_arch_i386 && native_arch != lxc_seccomp_arch_amd64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_i386; if (native_arch == lxc_seccomp_arch_amd64) { if (compat_ctx) continue; compat_ctx = get_new_ctx(lxc_seccomp_arch_i386, default_policy_action); if (!compat_ctx) goto bad; } } else if (strcmp(line, "[X86_64]") == 0 || strcmp(line, "[x86_64]") == 0) { if (native_arch != lxc_seccomp_arch_amd64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_amd64; } else if (strcmp(line, "[all]") == 0 || strcmp(line, "[ALL]") == 0) { cur_rule_arch = lxc_seccomp_arch_all; if (native_arch == lxc_seccomp_arch_amd64 && !compat_ctx) { if (compat_ctx) continue; compat_ctx = get_new_ctx(lxc_seccomp_arch_i386, default_policy_action); if (!compat_ctx) goto bad; } } #ifdef SCMP_ARCH_ARM else if (strcmp(line, "[arm]") == 0 || strcmp(line, "[ARM]") == 0) { if (native_arch != lxc_seccomp_arch_arm) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_arm; } #endif #ifdef SCMP_ARCH_PPC64LE else if (strcmp(line, "[ppc64le]") == 0 || strcmp(line, "[PPC64LE]") == 0) { if (native_arch != lxc_seccomp_arch_ppc64le) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_ppc64le; } #endif #ifdef SCMP_ARCH_PPC64 else if (strcmp(line, "[ppc64]") == 0 || strcmp(line, "[PPC64]") == 0) { if (native_arch != lxc_seccomp_arch_ppc64) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_ppc64; } #endif #ifdef SCMP_ARCH_PPC else if (strcmp(line, "[ppc]") == 0 || strcmp(line, "[PPC]") == 0) { if (native_arch != lxc_seccomp_arch_ppc) { cur_rule_arch = lxc_seccomp_arch_unknown; continue; } cur_rule_arch = lxc_seccomp_arch_ppc; } #endif else goto bad_arch; continue; } /* irrelevant arch - i.e. arm on i386 */ if (cur_rule_arch == lxc_seccomp_arch_unknown) continue; /* read optional action which follows the syscall */ action = get_and_clear_v2_action(line, default_rule_action); if (action == -1) { ERROR("Failed to interpret action"); goto bad_rule; } /* * TODO generalize - if !is_compat_only(native_arch, cur_rule_arch) * * in other words, the rule is 32-bit only, on 64-bit host; don't run * the rule against the native arch. */ if (!(cur_rule_arch == lxc_seccomp_arch_i386 && native_arch == lxc_seccomp_arch_amd64)) { INFO("Adding non-compat rule for %s action %d", line, action); if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action)) goto bad_rule; } /* * TODO generalize - if need_compat(native_arch, cur_rule_arch) */ if (native_arch == lxc_seccomp_arch_amd64 && cur_rule_arch != lxc_seccomp_arch_amd64) { int nr1, nr2; INFO("Adding compat rule for %s action %d", line, action); nr1 = seccomp_syscall_resolve_name_arch(SCMP_ARCH_X86, line); nr2 = seccomp_syscall_resolve_name_arch(SCMP_ARCH_NATIVE, line); if (nr1 == nr2) { /* If the syscall # is the same for 32- and 64-bit, then we cannot * apply it to the compat_ctx. So apply it to the noncompat ctx. * We may already have done so, but that's ok */ INFO("Adding non-compat rule bc nr1 == nr2 (%d, %d)", nr1, nr2); if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action)) goto bad_rule; continue; } INFO("Really adding compat rule bc nr1 == nr2 (%d, %d)", nr1, nr2); if (!do_resolve_add_rule(SCMP_ARCH_X86, line, compat_ctx, action)) goto bad_rule; } } if (compat_ctx) { INFO("Merging in the compat seccomp ctx into the main one"); if (seccomp_merge(conf->seccomp_ctx, compat_ctx) != 0) { ERROR("Error merging i386 seccomp contexts"); goto bad; } } return 0; bad_arch: ERROR("Unsupported arch: %s", line); bad_rule: bad: if (compat_ctx) seccomp_release(compat_ctx); return -1; }
/* * v2 consists of * [x86] * open * read * write * close * # a comment * [x86_64] * open * read * write * close */ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf) { #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH char *p; int ret; scmp_filter_ctx *ctx = NULL; bool blacklist = false; uint32_t default_policy_action = -1, default_rule_action = -1, action; uint32_t arch = SCMP_ARCH_NATIVE; if (strncmp(line, "blacklist", 9) == 0) blacklist = true; else if (strncmp(line, "whitelist", 9) != 0) { ERROR("Bad seccomp policy style: %s", line); return -1; } if ((p = strchr(line, ' '))) { default_policy_action = get_v2_default_action(p+1); if (default_policy_action == -2) return -1; } /* for blacklist, allow any syscall which has no rule */ if (blacklist) { if (default_policy_action == -1) default_policy_action = SCMP_ACT_ALLOW; if (default_rule_action == -1) default_rule_action = SCMP_ACT_KILL; } else { if (default_policy_action == -1) default_policy_action = SCMP_ACT_KILL; if (default_rule_action == -1) default_rule_action = SCMP_ACT_ALLOW; } if (default_policy_action != SCMP_ACT_KILL) { ret = seccomp_reset(conf->seccomp_ctx, default_policy_action); if (ret != 0) { ERROR("Error re-initializing seccomp"); return -1; } if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) { ERROR("failed to turn off n-new-privs"); return -1; } } while (fgets(line, 1024, f)) { int nr; if (line[0] == '#') continue; if (strlen(line) == 0) continue; remove_trailing_newlines(line); INFO("processing: .%s.", line); if (line[0] == '[') { // read the architecture for next set of rules if (strcmp(line, "[x86]") == 0 || strcmp(line, "[X86]") == 0) arch = SCMP_ARCH_X86; else if (strcmp(line, "[X86_64]") == 0 || strcmp(line, "[x86_64]") == 0) arch = SCMP_ARCH_X86_64; #ifdef SCMP_ARCH_ARM else if (strcmp(line, "[arm]") == 0 || strcmp(line, "[ARM]") == 0) arch = SCMP_ARCH_ARM; #endif else goto bad_arch; if (ctx) { ERROR("Only two arch sections per policy supported"); goto bad_arch; } if ((ctx = seccomp_init(default_policy_action)) == NULL) { ERROR("Error initializing seccomp context"); return -1; } if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)) { ERROR("failed to turn off n-new-privs"); seccomp_release(ctx); return -1; } ret = seccomp_arch_add(ctx, arch); if (ret == -EEXIST) { seccomp_release(ctx); ctx = NULL; continue; } if (ret != 0) { ERROR("Error %d adding arch: %s", ret, line); goto bad_arch; } if (seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE) != 0) { ERROR("Error removing native arch from %s", line); goto bad_arch; } continue; } action = get_and_clear_v2_action(line, default_rule_action); if (action == -1) { ERROR("Failed to interpret action"); goto bad_rule; } nr = seccomp_syscall_resolve_name_arch(arch, line); if (nr < 0) { ERROR("Failed to resolve syscall: %s", line); goto bad_rule; } ret = seccomp_rule_add(ctx ? ctx : conf->seccomp_ctx, action, nr, 0); if (ret < 0) { ERROR("failed (%d) loading rule for %s", ret, line); goto bad_rule; } } if (ctx) { if (seccomp_merge(conf->seccomp_ctx, ctx) != 0) { seccomp_release(ctx); ERROR("Error merging seccomp contexts"); return -1; } } return 0; bad_arch: ERROR("Unsupported arch: %s", line); bad_rule: if (ctx) seccomp_release(ctx); return -1; #else return -1; #endif }