[lxc-devel] [lxc/master] Fix issue #1564, add seccomp limit syscall argument
lifeng68 on Github
lxc-bot at linuxcontainers.org
Thu Nov 23 10:58:22 UTC 2017
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 1421 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20171123/2f280421/attachment.bin>
-------------- next part --------------
From cbea56a0bb5e38397168c66ea1ff86da1c8885bf Mon Sep 17 00:00:00 2001
From: LiFeng <lifeng68 at 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 <lifeng68 at 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;
}
}
More information about the lxc-devel
mailing list