The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxc/pull/1942
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === Fix issue #1564 To support limit syscall arguments, extend the version 2 file to the following format: ``` syscall_name default_action args:num [index,value,valueTwo,op]... ``` num: the number of the, the maximum of num is 6 (type uint, unsigned decimal integer) For one arguments, [index,value,valueTwo,op] index: the index for syscall arguments (type uint, unsigned decimal integer) value: the value for syscall arguments (type uint64, unsigned decimal integer) valueTwo: the value for syscall arguments (type uint64, unsigned decimal integer) op: the operator for syscall arguments (type string), a valid list of constants as of libseccomp v2.3.2 is SCMP_CMP_NE,SCMP_CMP_LE,SCMP_CMP_LE, SCMP_CMP_EQ, SCMP_CMP_GE, SCMP_CMP_GT, SCMP_CMP_MASKED_EQ. For example: ``` 2 blacklist reject_force_umount # comment this to allow umount -f; not recommended [all] kexec_load errno 1 args:3 [0,1,0,SCMP_CMP_LE][3,1,0,SCMP_CMP_GT][5,1,0,SCMP_CMP_MASKED_EQ] open_by_handle_at errno 1 init_module errno 1 finit_module errno 1 delete_module errno 1 ``` Signed-off-by: LiFeng <lifen...@huawei.com>
From cbea56a0bb5e38397168c66ea1ff86da1c8885bf Mon Sep 17 00:00:00 2001 From: LiFeng <lifen...@huawei.com> Date: Thu, 23 Nov 2017 14:15:23 -0500 Subject: [PATCH] Fix issue #1564,add seccomp limit syscall argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To support limit syscall arguments, extend the version 2 file to the following format: ``` syscall_name default_action args:num [index,value,valueTwo,op]... ``` num: the number of the, the maximum of num is 6。 for one arguments, [index,value,valueTwo,op] index: the index for syscall arguments(type uint, unsigned decimal integer) value: the value for syscall arguments (type uint64, unsigned decimal integer) valueTwo: the value for syscall arguments (type uint64, unsigned decimal integer) op: the operator for syscall arguments(string), a valid list of constants as of libseccomp v2.3.2 is SCMP_CMP_NE,SCMP_CMP_LE,SCMP_CMP_LE, SCMP_CMP_EQ, SCMP_CMP_GE, SCMP_CMP_GT, SCMP_CMP_MASKED_EQ. For example: ``` 2 blacklist reject_force_umount # comment this to allow umount -f; not recommended [all] kexec_load errno 1 args:3 [0,1,0,SCMP_CMP_LE][3,1,0,SCMP_CMP_GT][5,1,0,SCMP_CMP_MASKED_EQ] open_by_handle_at errno 1 init_module errno 1 finit_module errno 1 delete_module errno 1 ``` Signed-off-by: LiFeng <lifen...@huawei.com> --- src/lxc/seccomp.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 191 insertions(+), 23 deletions(-) diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c index deacd1217..c7387e804 100644 --- a/src/lxc/seccomp.c +++ b/src/lxc/seccomp.c @@ -109,14 +109,13 @@ static const char *get_action_name(uint32_t action) } } -static uint32_t get_and_clear_v2_action(char *line, uint32_t def_action) +static uint32_t get_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++; @@ -129,6 +128,151 @@ static uint32_t get_and_clear_v2_action(char *line, uint32_t def_action) default: return ret; } } + +struct v2_rule_args { + uint32_t index; + uint64_t value; + uint64_t mask; + enum scmp_compare op; +}; + +struct seccomp_v2_rule { + uint32_t action; + uint32_t args_num; + struct v2_rule_args args_value[6]; +}; + +static enum scmp_compare parse_v2_rule_op(char *s) +{ + enum scmp_compare ret; + + if (strcmp(s, "SCMP_CMP_NE") == 0) + ret = SCMP_CMP_NE; + else if (strcmp(s, "SCMP_CMP_LT") == 0) + ret = SCMP_CMP_LT; + else if (strcmp(s, "SCMP_CMP_LE") == 0) + ret = SCMP_CMP_LE; + else if (strcmp(s, "SCMP_CMP_EQ") == 0) + ret = SCMP_CMP_EQ; + else if (strcmp(s, "SCMP_CMP_GE") == 0) + ret = SCMP_CMP_GE; + else if (strcmp(s, "SCMP_CMP_GT") == 0) + ret = SCMP_CMP_GT; + else if (strcmp(s, "SCMP_CMP_MASKED_EQ") == 0) + ret = SCMP_CMP_MASKED_EQ; + else + ret = -1; + + return ret; +} + +static uint32_t get_seccomp_arg_num(char *line) +{ + uint32_t num = -1; + char *tmp = NULL; + int ret = 0; + + /*read optional args which follows the syscall*/ + tmp = strstr(line, "args:"); + if (!tmp) { + INFO("Seccomp rule include none args"); + return 0; + } + + ret = sscanf(tmp, "args:%u", &num); + if (ret != 1 || num > 6) { + INFO("Failed to interpret valid args number"); + return -1; + } + + return num; +} + +static int get_seccomp_arg_value(char *key, struct v2_rule_args *rule_args) +{ + int ret = 0; + uint64_t value = 0; + uint64_t mask = 0; + enum scmp_compare op = 0; + uint32_t index = 0; + char s[30] = {0}; + char *tmp = NULL; + + memset(s, 0x00, sizeof(s)); + tmp = strchr(key, '['); + if (!tmp) { + ERROR("Failed to interpret args."); + return -1; + } + ret = sscanf(tmp, "[%u,%llu,%llu,%30s", &index, (long long unsigned int *)&value, (long long unsigned int *)&mask, s); + if (ret != 4 || index >= 6) { + ERROR("Failed to interpret args value."); + return -1; + } + + op = parse_v2_rule_op(s); + if (op == -1) { + ERROR("Failed to interpret args operator value."); + return -1; + } + + rule_args->index = index; + rule_args->value = value; + rule_args->mask = mask; + rule_args->op = op; + return 0; +} + +static int parse_v2_rules(char *line, uint32_t def_action, struct seccomp_v2_rule *rules) +{ + int ret = 0 ; + int i = 0; + char *tmp = NULL; + char *key = NULL; + char *saveptr = NULL; + + tmp = strdup(line); + if (!tmp) + return -1; + + /* read optional action which follows the syscall */ + rules->action = get_v2_action(tmp, def_action); + if (rules->action == -1) { + ERROR("Failed to interpret action."); + ret = -1; + goto out; + } + + rules->args_num = get_seccomp_arg_num(tmp); + if (rules->args_num == -1) { + ret = -1; + goto out; + } + if (rules->args_num == 0) { + ret = 0; + goto out; + } + + for ((key = strtok_r(tmp, "]", &saveptr)), i = 0; key && i < rules->args_num; (key = strtok_r(NULL, "]", &saveptr)), i++) { + ret = get_seccomp_arg_value(key, &rules->args_value[i]); + if (ret) { + ret = -1; + goto out; + } + } + if (i != rules->args_num) { + ERROR("Failed to interpret sufficient parameters."); + ret = -1; + goto out; + } + + ret = 0; +out: + if (tmp) + free(tmp); + return ret; +} + #endif #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH @@ -260,9 +404,12 @@ scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_ } bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx, - uint32_t action) + struct seccomp_v2_rule *rule) { - int nr, ret; + int nr, ret, i; + struct scmp_arg_cmp arg_cmp[6]; + + memset(arg_cmp, 0x00 ,sizeof(arg_cmp)); ret = seccomp_arch_exist(ctx, arch); if (arch && ret != 0) { @@ -272,6 +419,11 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx, return false; } + /*get the syscall name*/ + char *p = strchr(line, ' '); + if (p) + *p = '\0'; + if (strncmp(line, "reject_force_umount", 19) == 0) { INFO("Setting Seccomp rule to reject force umounts."); ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(umount2), @@ -296,10 +448,24 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx, WARN("This syscall will NOT be blacklisted."); return true; } - ret = seccomp_rule_add_exact(ctx, action, nr, 0); + + for (i = 0; i < rule->args_num; i++) { + INFO("arg_cmp[%d]:SCMP_CMP(%u, %llu, %llu, %llu)", i, + rule->args_value[i].index, + (long long unsigned int)rule->args_value[i].op, + (long long unsigned int)rule->args_value[i].mask, + (long long unsigned int)rule->args_value[i].value); + + if (SCMP_CMP_MASKED_EQ == rule->args_value[i].op) + arg_cmp[i] = SCMP_CMP(rule->args_value[i].index, rule->args_value[i].op, rule->args_value[i].mask, rule->args_value[i].value); + else + arg_cmp[i] = SCMP_CMP(rule->args_value[i].index, rule->args_value[i].op, rule->args_value[i].value); + } + + ret = seccomp_rule_add_exact_array(ctx, rule->action, nr, rule->args_num, arg_cmp); if (ret < 0) { ERROR("Failed (%d) loading rule for %s (nr %d action %d(%s)): %s.", - ret, line, nr, action, get_action_name(action), strerror(-ret)); + ret, line, nr, rule->action, get_action_name(rule->action), strerror(-ret)); return false; } return true; @@ -325,10 +491,11 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf) int ret; scmp_filter_ctx compat_ctx[2] = {NULL, NULL}; bool blacklist = false; - uint32_t default_policy_action = -1, default_rule_action = -1, action; + uint32_t default_policy_action = -1, default_rule_action = -1; enum lxc_hostarch_t native_arch = get_hostarch(), cur_rule_arch = native_arch; uint32_t compat_arch[2] = {SCMP_ARCH_NATIVE, SCMP_ARCH_NATIVE}; + struct seccomp_v2_rule rule; if (strncmp(line, "blacklist", 9) == 0) blacklist = true; @@ -580,19 +747,20 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf) if (cur_rule_arch == lxc_seccomp_arch_unknown) continue; + memset(&rule, 0x00, sizeof(rule)); /* 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."); + ret = parse_v2_rules(line, default_rule_action, &rule); + if (ret != 0) { + ERROR("Failed to interpret seccomp rule."); 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(%s).", line, action, - get_action_name(action)); - if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action)) + INFO("Adding native rule for %s action %d(%s).", line, rule.action, + get_action_name(rule.action)); + if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, &rule)) goto bad_rule; } else if (cur_rule_arch != lxc_seccomp_arch_all) { @@ -600,22 +768,22 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf) 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(%s).", line, action, - get_action_name(action)); - if (!do_resolve_add_rule(compat_arch[arch_index], line, compat_ctx[arch_index], action)) + INFO("Adding compat-only rule for %s action %d(%s).", line, rule.action, + get_action_name(rule.action)); + if (!do_resolve_add_rule(compat_arch[arch_index], line, compat_ctx[arch_index], &rule)) goto bad_rule; } else { - INFO("Adding native rule for %s action %d(%s).", line, action, - get_action_name(action)); - if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action)) + INFO("Adding native rule for %s action %d(%s).", line, rule.action, + get_action_name(rule.action)); + if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, &rule)) goto bad_rule; - INFO("Adding compat rule for %s action %d(%s).", line, action, - get_action_name(action)); - if (!do_resolve_add_rule(compat_arch[0], line, compat_ctx[0], action)) + INFO("Adding compat rule for %s action %d(%s).", line, rule.action, + get_action_name(rule.action)); + if (!do_resolve_add_rule(compat_arch[0], line, compat_ctx[0], &rule)) goto bad_rule; if (compat_arch[1] != SCMP_ARCH_NATIVE && - !do_resolve_add_rule(compat_arch[1], line, compat_ctx[1], action)) + !do_resolve_add_rule(compat_arch[1], line, compat_ctx[1], &rule)) goto bad_rule; } }
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel