On Wed, Feb 12, 2014 at 03:50:20PM -0600, Serge Hallyn wrote: > v2 allows specifying system calls by name, and specifying > architecture. A policy looks like: > > 2 > whitelist > open > read > write > close > mount > [x86] > open > read > > Also use SCMP_ACT_KILL by default rather than SCMP_ACT_ERRNO(31) - > which confusingly returns 'EMLINK' on x86_64. Note this change > is also done for v1 as I think it is worthwhile. > > With this patch, I can in fact use a seccomp policy like: > > 2 > blacklist > mknod errno 0 > > after which 'sudo mknod null c 1 3' silently succeeds without > creating the null device. > > changelog v2: > add blacklist support > support default action > support per-rule action > > Signed-off-by: Serge Hallyn <[email protected]>
Looks good to me. Can I just ask you to send another patch updating our documentation? It currently only lists v1 and says that only whitelist is allowed (lxc.container.conf.sgml). Adding seccomp-v1 and seccomp-v2 example files to doc/ may also be worthwhile. Acked-by: Stéphane Graber <[email protected]> > --- > src/lxc/seccomp.c | 257 > +++++++++++++++++++++++++++++++++++++++++++++++++----- > 1 file changed, 236 insertions(+), 21 deletions(-) > > diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c > index ea23b3a..4c01be7 100644 > --- a/src/lxc/seccomp.c > +++ b/src/lxc/seccomp.c > @@ -34,6 +34,233 @@ > > 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'; > +} > + > +static uint32_t get_v2_default_action(char *line) > +{ > + uint32_t ret_action = -1; > + > + while (*line == ' ') line++; > + // after 'whitelist' or 'blacklist' comes default behavior > + if (strncmp(line, "kill", 4) == 0) > + ret_action = SCMP_ACT_KILL; > + else if (strncmp(line, "errno", 5) == 0) { > + int e; > + if (sscanf(line+5, "%d", &e) != 1) { > + ERROR("Bad errno value in %s", line); > + return -2; > + } > + ret_action = SCMP_ACT_ERRNO(e); > + } else if (strncmp(line, "allow", 5) == 0) > + ret_action = SCMP_ACT_ALLOW; > + else if (strncmp(line, "trap", 4) == 0) > + ret_action = SCMP_ACT_TRAP; > + return ret_action; > +} > + > +static uint32_t get_and_clear_v2_action(char *line, uint32_t def_action) > +{ > + char *p = strchr(line, ' '); > + uint32_t ret; > + > + if (!p) > + return def_action; > + *p = '\0'; > + p++; > + while (*p == ' ') > + p++; > + if (!*p || *p == '#') > + return def_action; > + ret = get_v2_default_action(p); > + switch(ret) { > + case -2: return -1; > + case -1: return def_action; > + default: return ret; > + } > +} > + > +/* > + * 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_SCMP_FILTER_CTX > + 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; > + 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(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 > +} > + > /* > * The first line of the config file has a policy language version > * the second line has some directives > @@ -48,7 +275,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; > } > @@ -56,31 +283,19 @@ static int parse_config(FILE *f, struct lxc_conf *conf) > ERROR("invalid config file"); > return -1; > } > - if (!strstr(line, "whitelist")) { > + if (version == 1 && !strstr(line, "whitelist")) { > ERROR("only whitelist policy is supported"); > return -1; > } > + > if (strstr(line, "debug")) { > 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, line, conf); > } > > int lxc_read_seccomp_config(struct lxc_conf *conf) > @@ -93,10 +308,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 -- Stéphane Graber Ubuntu developer http://www.ubuntu.com
signature.asc
Description: Digital signature
_______________________________________________ lxc-devel mailing list [email protected] http://lists.linuxcontainers.org/listinfo/lxc-devel
