diff options
author | Paul Moore <pmoore@redhat.com> | 2015-12-17 19:07:47 -0500 |
---|---|---|
committer | Paul Moore <paul@paul-moore.com> | 2016-02-09 08:32:15 -0500 |
commit | f16f405f61ecdbad202257b61004b85fce64d75c (patch) | |
tree | 2f7d4969994f44bcd4dfe4bc66a72b850647e8c6 | |
parent | a4478ddcd4e3b34fcd9c526dcf54f0d79b33ac16 (diff) | |
download | libseccomp-f16f405f61ecdbad202257b61004b85fce64d75c.tar.gz |
db: store the rules used to build the filter
This will be useful in future patches for rebuilding and manipulating
the filter.
Signed-off-by: Paul Moore <pmoore@redhat.com>
-rw-r--r-- | src/arch-x86.c | 37 | ||||
-rw-r--r-- | src/arch-x86.h | 2 | ||||
-rw-r--r-- | src/arch.c | 13 | ||||
-rw-r--r-- | src/arch.h | 6 | ||||
-rw-r--r-- | src/db.c | 101 | ||||
-rw-r--r-- | src/db.h | 12 |
6 files changed, 110 insertions, 61 deletions
diff --git a/src/arch-x86.c b/src/arch-x86.c index a08ffdf..4877b3c 100644 --- a/src/arch-x86.c +++ b/src/arch-x86.c @@ -65,8 +65,7 @@ int x86_syscall_rewrite(const struct arch_def *arch, int *syscall) * Rewrite a filter rule to match the architecture specifics * @param arch the architecture definition * @param strict strict flag - * @param syscall the syscall number - * @param chain the argument filter chain + * @param rule the filter rule * * Syscalls can vary across different architectures so this function handles * the necessary seccomp rule rewrites to ensure the right thing is done @@ -77,11 +76,11 @@ int x86_syscall_rewrite(const struct arch_def *arch, int *syscall) * */ int x86_filter_rewrite(const struct arch_def *arch, bool strict, - int *syscall, struct db_api_arg *chain) + struct db_api_rule_list *rule) { - int sys = *syscall; - unsigned int iter; int arg_max; + unsigned int iter; + int sys = rule->syscall; arg_max = arch_arg_count_max(arch); if (arg_max < 0) @@ -89,26 +88,26 @@ int x86_filter_rewrite(const struct arch_def *arch, bool strict, if (sys <= -100 && sys >= -117) { for (iter = 0; iter < arg_max; iter++) { - if ((chain[iter].valid != 0) && (strict)) + if ((rule->args[iter].valid != 0) && (strict)) return -EINVAL; } - chain[0].arg = 0; - chain[0].op = SCMP_CMP_EQ; - chain[0].mask = DATUM_MAX; - chain[0].datum = abs(sys) % 100; - chain[0].valid = 1; - *syscall = __x86_NR_socketcall; + rule->args[0].arg = 0; + rule->args[0].op = SCMP_CMP_EQ; + rule->args[0].mask = DATUM_MAX; + rule->args[0].datum = abs(sys) % 100; + rule->args[0].valid = 1; + rule->syscall = __x86_NR_socketcall; } else if (sys <= -200 && sys >= -211) { for (iter = 0; iter < arg_max; iter++) { - if ((chain[iter].valid != 0) && (strict)) + if ((rule->args[iter].valid != 0) && (strict)) return -EINVAL; } - chain[0].arg = 0; - chain[0].op = SCMP_CMP_EQ; - chain[0].mask = DATUM_MAX; - chain[0].datum = abs(sys) % 200; - chain[0].valid = 1; - *syscall = __x86_NR_ipc; + rule->args[0].arg = 0; + rule->args[0].op = SCMP_CMP_EQ; + rule->args[0].mask = DATUM_MAX; + rule->args[0].datum = abs(sys) % 200; + rule->args[0].valid = 1; + rule->syscall = __x86_NR_ipc; } else if (sys < 0) return -EDOM; diff --git a/src/arch-x86.h b/src/arch-x86.h index 6190519..8460bbe 100644 --- a/src/arch-x86.h +++ b/src/arch-x86.h @@ -38,6 +38,6 @@ const char *x86_syscall_iterate_name(unsigned int spot); int x86_syscall_rewrite(const struct arch_def *arch, int *syscall); int x86_filter_rewrite(const struct arch_def *arch, bool strict, - int *syscall, struct db_api_arg *chain); + struct db_api_rule_list *rule); #endif @@ -441,8 +441,7 @@ int arch_syscall_rewrite(const struct arch_def *arch, int *syscall) * Rewrite a filter rule to match the architecture specifics * @param arch the architecture definition * @param strict strict flag - * @param syscall the syscall number - * @param chain the argument filter chain + * @param rule the filter rule * * Syscalls can vary across different architectures so this function handles * the necessary seccomp rule rewrites to ensure the right thing is done @@ -453,11 +452,11 @@ int arch_syscall_rewrite(const struct arch_def *arch, int *syscall) * @arch, and negative values on failure. * */ -int arch_filter_rewrite(const struct arch_def *arch, - bool strict, int *syscall, struct db_api_arg *chain) +int arch_filter_rewrite(const struct arch_def *arch, bool strict, + struct db_api_rule_list *rule) { int rc; - int sys = *syscall; + int sys = rule->syscall; if (sys >= 0) { /* we shouldn't be here - no rewrite needed */ @@ -469,7 +468,7 @@ int arch_filter_rewrite(const struct arch_def *arch, /* rewritable syscalls */ switch (arch->token) { case SCMP_ARCH_X86: - rc = x86_filter_rewrite(arch, strict, syscall, chain); + rc = x86_filter_rewrite(arch, strict, rule); /* we still want to catch invalid rewrites */ if (rc == -EINVAL) return -EINVAL; @@ -477,7 +476,7 @@ int arch_filter_rewrite(const struct arch_def *arch, } /* syscalls not defined on this architecture */ - if ((*syscall) < 0) + if (rule->syscall < 0) return -EDOM; return 0; } @@ -30,7 +30,7 @@ #include "system.h" -struct db_api_arg; +struct db_api_rule_list; struct arch_def { uint32_t token; @@ -92,7 +92,7 @@ const char *arch_syscall_resolve_num(const struct arch_def *arch, int num); int arch_syscall_translate(const struct arch_def *arch, int *syscall); int arch_syscall_rewrite(const struct arch_def *arch, int *syscall); -int arch_filter_rewrite(const struct arch_def *arch, - bool strict, int *syscall, struct db_api_arg *chain); +int arch_filter_rewrite(const struct arch_def *arch, bool strict, + struct db_api_rule_list *rule); #endif @@ -357,6 +357,7 @@ next: static void _db_reset(struct db_filter *db) { struct db_sys_list *s_iter; + struct db_api_rule_list *r_iter; if (db == NULL) return; @@ -372,6 +373,20 @@ static void _db_reset(struct db_filter *db) } db->syscalls = NULL; } + + /* free any rules */ + if (db->rules != NULL) { + /* split the loop first then loop and free */ + db->rules->prev->next = NULL; + r_iter = db->rules; + while (r_iter != NULL) { + db->rules = r_iter->next; + free(r_iter->args); + free(r_iter); + r_iter = db->rules; + } + db->rules = NULL; + } } /** @@ -1172,9 +1187,7 @@ gen_32_failure: /** * Add a new rule to the seccomp filter DB * @param db the seccomp filter db - * @param action the filter action - * @param syscall the syscall number - * @param chain argument filter chain + * @param rule the filter rule * * This function adds a new syscall filter to the seccomp filter DB, adding to * the existing filters for the syscall, unless no argument specific filters @@ -1183,10 +1196,13 @@ gen_32_failure: * filter DB. Returns zero on success, negative values on failure. * */ -int _db_rule_add(struct db_filter *db, uint32_t action, int syscall, - struct db_api_arg *chain) +static int _db_rule_add(struct db_filter *db, + const struct db_api_rule_list *rule) { int rc = -ENOMEM; + int syscall = rule->syscall; + uint32_t action = rule->action; + struct db_api_arg *chain = rule->args; struct db_sys_list *s_new, *s_iter, *s_prev = NULL; struct db_arg_chain_tree *c_iter = NULL, *c_prev = NULL; struct db_arg_chain_tree *ec_iter; @@ -1515,13 +1531,13 @@ int db_col_rule_add(struct db_filter_col *col, unsigned int arg_cnt, const struct scmp_arg_cmp *arg_array) { int rc = 0, rc_tmp; - int sc_tmp; unsigned int iter; unsigned int chain_len; unsigned int arg_num; size_t chain_size; struct db_filter *filter; - struct db_api_arg *chain = NULL, *chain_tmp; + struct db_api_arg *chain = NULL; + struct db_api_rule_list *rule; struct scmp_arg_cmp arg_data; /* collect the arguments for the filter rule */ @@ -1566,41 +1582,64 @@ int db_col_rule_add(struct db_filter_col *col, for (iter = 0; iter < col->filter_cnt; iter++) { filter = col->filters[iter]; - sc_tmp = syscall; - rc_tmp = arch_syscall_translate(filter->arch, &sc_tmp); - if (rc_tmp < 0) + /* copy of the chain for each filter in the collection */ + rule = malloc(sizeof(*rule)); + if (rule == NULL) { + rc_tmp = -ENOMEM; + goto add_failure; + } + rule->args = malloc(chain_size); + if (rule->args == NULL) { + free(rule); + rc_tmp = -ENOMEM; + goto add_failure; + } + rule->action = action; + rule->syscall = syscall; + rule->args_cnt = chain_len; + memcpy(rule->args, chain, chain_size); + + rc_tmp = arch_syscall_translate(filter->arch, &rule->syscall); + if (rc_tmp < 0) { + free(rule->args); + free(rule); goto add_failure; + } /* if this is a pseudo syscall (syscall < 0) then we need to * rewrite the rule for some arch specific reason */ - if (sc_tmp < 0) { - /* make a private copy of the chain */ - chain_tmp = malloc(chain_size); - if (chain_tmp == NULL) { - rc = -ENOMEM; - goto add_failure; - } - memcpy(chain_tmp, chain, chain_size); - + if (rule->syscall < 0) { /* mangle the private chain copy */ rc_tmp = arch_filter_rewrite(filter->arch, strict, - &sc_tmp, chain_tmp); - if ((rc_tmp == -EDOM) && (!strict)) { - free(chain_tmp); - continue; - } + rule); if (rc_tmp < 0) { - free(chain_tmp); + free(rule->args); + free(rule); + if ((rc_tmp == -EDOM) && (!strict)) + continue; goto add_failure; } + } - /* add the new rule to the existing filter */ - rc_tmp = _db_rule_add(filter, action, sc_tmp, chain_tmp); - free(chain_tmp); - } else - /* add the new rule to the existing filter */ - rc_tmp = _db_rule_add(filter, action, sc_tmp, chain); + /* add the new rule to the existing filter */ + rc_tmp = _db_rule_add(filter, rule); + if (rc_tmp == 0) { + /* insert the chain to the end of the filter's rule list */ + if (filter->rules != NULL) { + rule->prev = filter->rules->prev; + rule->next = filter->rules; + filter->rules->prev->next = rule; + filter->rules->prev = rule; + } else { + rule->prev = rule; + rule->next = rule; + filter->rules = rule; + } + } else { + free(rule->args); + free(rule); + } add_failure: if (rc == 0 && rc_tmp < 0) @@ -40,6 +40,15 @@ struct db_api_arg { bool valid; }; +struct db_api_rule_list { + uint32_t action; + int syscall; + struct db_api_arg *args; + unsigned int args_cnt; + + struct db_api_rule_list *prev, *next; +}; + struct db_arg_chain_tree { /* argument number (a0 = 0, a1 = 1, etc.) */ unsigned int arg; @@ -137,6 +146,9 @@ struct db_filter { /* syscall filters, kept as a sorted single-linked list */ struct db_sys_list *syscalls; + + /* list of rules used to build the filters, kept in order */ + struct db_api_rule_list *rules; }; struct db_filter_col { |