v2 allows specifying system calls by name, and specifying architecture. A policy might look like:
2 whitelist # native architecture is x86_64; we could put # [x86-64] here but don't need to open read write close mount # let's also allow some 32-bit syscalls [x86] open read Also use SCMP_ACT_KILL rather than SCMP_ACT_ERRNO(31) - which confusingly returns 'EMLINK' on x86_64. Signed-off-by: Serge Hallyn <[email protected]> --- src/lxc/seccomp.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 144 insertions(+), 20 deletions(-) diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c index ea23b3a..c8c232a 100644 --- a/src/lxc/seccomp.c +++ b/src/lxc/seccomp.c @@ -34,6 +34,143 @@ lxc_log_define(lxc_seccomp, lxc); +static int parse_config_v1(FILE *f, struct lxc_conf *conf) +{ + char line[1024]; + int ret; + + while (fgets(line, 1024, f)) { + int nr; + ret = sscanf(line, "%d", &nr); + if (ret != 1) + return -1; + ret = seccomp_rule_add( +#if HAVE_SCMP_FILTER_CTX + conf->seccomp_ctx, +#endif + SCMP_ACT_ALLOW, nr, 0); + if (ret < 0) { + ERROR("failed loading allow rule for %d", nr); + return ret; + } + } + return 0; +} + +static void remove_trailing_newlines(char *l) +{ + char *p = l; + + while (*p) + p++; + while (--p >= l && *p == '\n') + *p = '\0'; +} + +/* + * v2 consists of + * [x86] + * open + * read + * write + * close + * # a comment + * [x86_64] + * open + * read + * write + * close + */ +static int parse_config_v2(FILE *f, struct lxc_conf *conf) +{ +#if HAVE_SCMP_FILTER_CTX + char line[1024]; + int ret; + uint32_t arch = SCMP_ARCH_NATIVE; + scmp_filter_ctx *ctx = NULL; + + 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] == '[') { + 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; + else if (strcmp(line, "[arm]") == 0 || + strcmp(line, "[ARM]") == 0) + arch = SCMP_ARCH_ARM; + else + goto bad_arch; + if (ctx) { + ERROR("Only two arch sections per policy supported"); + goto bad_arch; + } + if ((ctx = seccomp_init(SCMP_ACT_KILL)) == 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; + } + + 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, + SCMP_ACT_ALLOW, nr, 0); + if (ret < 0) { + ERROR("failed (%d) loading allow rule for %d", ret, nr); + 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 +} + /* * The first line of the config file has a policy language version * the second line has some directives @@ -48,7 +185,7 @@ static int parse_config(FILE *f, struct lxc_conf *conf) int ret, version; ret = fscanf(f, "%d\n", &version); - if (ret != 1 || version != 1) { + if (ret != 1 || (version != 1 && version != 2)) { ERROR("invalid version"); return -1; } @@ -64,23 +201,10 @@ static int parse_config(FILE *f, struct lxc_conf *conf) ERROR("debug not yet implemented"); return -1; } - /* now read in the whitelist entries one per line */ - while (fgets(line, 1024, f)) { - int nr; - ret = sscanf(line, "%d", &nr); - if (ret != 1) - return -1; - ret = seccomp_rule_add( -#if HAVE_SCMP_FILTER_CTX - conf->seccomp_ctx, -#endif - SCMP_ACT_ALLOW, nr, 0); - if (ret < 0) { - ERROR("failed loading allow rule for %d", nr); - return ret; - } - } - return 0; + + if (version == 1) + return parse_config_v1(f, conf); + return parse_config_v2(f, conf); } int lxc_read_seccomp_config(struct lxc_conf *conf) @@ -93,10 +217,10 @@ int lxc_read_seccomp_config(struct lxc_conf *conf) #if HAVE_SCMP_FILTER_CTX /* XXX for debug, pass in SCMP_ACT_TRAP */ - conf->seccomp_ctx = seccomp_init(SCMP_ACT_ERRNO(31)); + conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL); ret = !conf->seccomp_ctx; #else - ret = seccomp_init(SCMP_ACT_ERRNO(31)) < 0; + ret = seccomp_init(SCMP_ACT_KILL) < 0; #endif if (ret) { ERROR("failed initializing seccomp"); -- 1.9.rc1 _______________________________________________ lxc-devel mailing list [email protected] http://lists.linuxcontainers.org/listinfo/lxc-devel
