summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Moore <pmoore@redhat.com>2015-12-17 19:07:47 -0500
committerPaul Moore <paul@paul-moore.com>2016-02-09 08:32:15 -0500
commitf16f405f61ecdbad202257b61004b85fce64d75c (patch)
tree2f7d4969994f44bcd4dfe4bc66a72b850647e8c6
parenta4478ddcd4e3b34fcd9c526dcf54f0d79b33ac16 (diff)
downloadlibseccomp-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.c37
-rw-r--r--src/arch-x86.h2
-rw-r--r--src/arch.c13
-rw-r--r--src/arch.h6
-rw-r--r--src/db.c101
-rw-r--r--src/db.h12
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
diff --git a/src/arch.c b/src/arch.c
index 33f35a7..bb926d2 100644
--- a/src/arch.c
+++ b/src/arch.c
@@ -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;
}
diff --git a/src/arch.h b/src/arch.h
index 84e54e5..fcdfd7f 100644
--- a/src/arch.h
+++ b/src/arch.h
@@ -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
diff --git a/src/db.c b/src/db.c
index be63342..dc9ca71 100644
--- a/src/db.c
+++ b/src/db.c
@@ -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)
diff --git a/src/db.h b/src/db.h
index e1950c8..b611a10 100644
--- a/src/db.h
+++ b/src/db.h
@@ -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 {