From 996e445a74823c735757413fda809e1ed0afc7d4 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Sat, 2 Jan 2016 15:25:57 -0500 Subject: arch: move the low level filter rule addition code into the arch layer The arch specific filter rewrite code is going to need to become more complex so move the low level rule addition code directly into the arch layer instead of the db layer, but still keep the tree manipulation code in the db layer. This patch also creates a new arch specific rule_add() function table entry and allows for this function to create multiple rules from a single rule. Signed-off-by: Paul Moore --- src/Makefile.am | 18 ++++----- src/arch-aarch64.c | 1 + src/arch-arm.c | 1 + src/arch-mips.c | 2 + src/arch-mips64.c | 2 + src/arch-mips64n32.c | 2 + src/arch-ppc.c | 1 + src/arch-ppc64.c | 2 + src/arch-s390.c | 1 + src/arch-s390x.c | 1 + src/arch-x32.c | 1 + src/arch-x86.c | 1 + src/arch-x86_64.c | 1 + src/arch.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/arch.h | 9 ++++- src/db.c | 71 +++-------------------------------- src/db.h | 2 + 17 files changed, 140 insertions(+), 80 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index ba9b9f4..2cd8a1e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,7 +21,11 @@ if ENABLE_PYTHON SUBDIRS += python endif -SOURCES_ARCH = \ +SOURCES_ALL = \ + api.c system.h system.c \ + gen_pfc.h gen_pfc.c gen_bpf.h gen_bpf.c \ + hash.h hash.c \ + db.h db.c \ arch.c arch.h \ arch-x86.h arch-x86.c arch-x86-syscalls.c \ arch-x86_64.h arch-x86_64.c arch-x86_64-syscalls.c \ @@ -36,12 +40,6 @@ SOURCES_ARCH = \ arch-s390.h arch-s390.c arch-s390-syscalls.c \ arch-s390x.h arch-s390x.c arch-s390x-syscalls.c -SOURCES_GEN = \ - api.c system.h system.c \ - db.h db.c \ - hash.h hash.c \ - gen_pfc.h gen_pfc.c gen_bpf.h gen_bpf.c - EXTRA_DIST = arch-syscall-validate TESTS = arch-syscall-check @@ -50,11 +48,11 @@ check_PROGRAMS = arch-syscall-check arch-syscall-dump lib_LTLIBRARIES = libseccomp.la -arch_syscall_dump_SOURCES = arch-syscall-dump.c ${SOURCES_ARCH} +arch_syscall_dump_SOURCES = arch-syscall-dump.c ${SOURCES_ALL} -arch_syscall_check_SOURCES = arch-syscall-check.c ${SOURCES_ARCH} +arch_syscall_check_SOURCES = arch-syscall-check.c ${SOURCES_ALL} -libseccomp_la_SOURCES = ${SOURCES_GEN} ${SOURCES_ARCH} +libseccomp_la_SOURCES = ${SOURCES_ALL} libseccomp_la_CPPFLAGS = ${AM_CPPFLAGS} -I$(top_builddir)/include libseccomp_la_CFLAGS = ${AM_CFLAGS} ${CFLAGS} -fPIC -DPIC -fvisibility=hidden libseccomp_la_LDFLAGS = ${AM_LDFLAGS} ${LDFLAGS} \ diff --git a/src/arch-aarch64.c b/src/arch-aarch64.c index 6eb66f5..7b596db 100644 --- a/src/arch-aarch64.c +++ b/src/arch-aarch64.c @@ -35,4 +35,5 @@ const struct arch_def arch_def_aarch64 = { .syscall_resolve_num = aarch64_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; diff --git a/src/arch-arm.c b/src/arch-arm.c index 8207986..713f393 100644 --- a/src/arch-arm.c +++ b/src/arch-arm.c @@ -35,4 +35,5 @@ const struct arch_def arch_def_arm = { .syscall_resolve_num = arm_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; diff --git a/src/arch-mips.c b/src/arch-mips.c index 3684714..3c3dd8d 100644 --- a/src/arch-mips.c +++ b/src/arch-mips.c @@ -36,6 +36,7 @@ const struct arch_def arch_def_mips = { .syscall_resolve_num = mips_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; const struct arch_def arch_def_mipsel = { @@ -47,4 +48,5 @@ const struct arch_def arch_def_mipsel = { .syscall_resolve_num = mips_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; diff --git a/src/arch-mips64.c b/src/arch-mips64.c index a71864f..9327bb6 100644 --- a/src/arch-mips64.c +++ b/src/arch-mips64.c @@ -34,6 +34,7 @@ const struct arch_def arch_def_mips64 = { .syscall_resolve_num = mips64_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; const struct arch_def arch_def_mipsel64 = { @@ -45,4 +46,5 @@ const struct arch_def arch_def_mipsel64 = { .syscall_resolve_num = mips64_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; diff --git a/src/arch-mips64n32.c b/src/arch-mips64n32.c index b6a56e1..6831592 100644 --- a/src/arch-mips64n32.c +++ b/src/arch-mips64n32.c @@ -36,6 +36,7 @@ const struct arch_def arch_def_mips64n32 = { .syscall_resolve_num = mips64n32_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; const struct arch_def arch_def_mipsel64n32 = { @@ -47,4 +48,5 @@ const struct arch_def arch_def_mipsel64n32 = { .syscall_resolve_num = mips64n32_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; diff --git a/src/arch-ppc.c b/src/arch-ppc.c index 058b66b..3586422 100644 --- a/src/arch-ppc.c +++ b/src/arch-ppc.c @@ -34,4 +34,5 @@ const struct arch_def arch_def_ppc = { .syscall_resolve_num = ppc_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; diff --git a/src/arch-ppc64.c b/src/arch-ppc64.c index 087e2f3..2da9970 100644 --- a/src/arch-ppc64.c +++ b/src/arch-ppc64.c @@ -34,6 +34,7 @@ const struct arch_def arch_def_ppc64 = { .syscall_resolve_num = ppc64_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; const struct arch_def arch_def_ppc64le = { @@ -45,4 +46,5 @@ const struct arch_def arch_def_ppc64le = { .syscall_resolve_num = ppc64_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; diff --git a/src/arch-s390.c b/src/arch-s390.c index 31f082a..494c0de 100644 --- a/src/arch-s390.c +++ b/src/arch-s390.c @@ -19,4 +19,5 @@ const struct arch_def arch_def_s390 = { .syscall_resolve_num = s390_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; diff --git a/src/arch-s390x.c b/src/arch-s390x.c index 0a1fdc8..038622a 100644 --- a/src/arch-s390x.c +++ b/src/arch-s390x.c @@ -19,4 +19,5 @@ const struct arch_def arch_def_s390x = { .syscall_resolve_num = s390x_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; diff --git a/src/arch-x32.c b/src/arch-x32.c index c64f7b9..15ddb1d 100644 --- a/src/arch-x32.c +++ b/src/arch-x32.c @@ -36,4 +36,5 @@ const struct arch_def arch_def_x32 = { .syscall_resolve_num = x32_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; diff --git a/src/arch-x86.c b/src/arch-x86.c index 8954ec3..00c3a97 100644 --- a/src/arch-x86.c +++ b/src/arch-x86.c @@ -39,6 +39,7 @@ const struct arch_def arch_def_x86 = { .syscall_resolve_num = x86_syscall_resolve_num, .syscall_rewrite = x86_syscall_rewrite, .filter_rewrite = x86_filter_rewrite, + .rule_add = NULL, }; /** diff --git a/src/arch-x86_64.c b/src/arch-x86_64.c index b5453b3..17beaea 100644 --- a/src/arch-x86_64.c +++ b/src/arch-x86_64.c @@ -35,4 +35,5 @@ const struct arch_def arch_def_x86_64 = { .syscall_resolve_num = x86_64_syscall_resolve_num, .syscall_rewrite = NULL, .filter_rewrite = NULL, + .rule_add = NULL, }; diff --git a/src/arch.c b/src/arch.c index f9bec47..0fc0062 100644 --- a/src/arch.c +++ b/src/arch.c @@ -42,6 +42,7 @@ #include "arch-ppc64.h" #include "arch-s390.h" #include "arch-s390x.h" +#include "db.h" #include "system.h" #define default_arg_count_max 6 @@ -394,8 +395,8 @@ 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, - struct db_api_rule_list *rule) +static int arch_filter_rewrite(const struct arch_def *arch, bool strict, + struct db_api_rule_list *rule) { int rc; int sys = rule->syscall; @@ -421,3 +422,102 @@ int arch_filter_rewrite(const struct arch_def *arch, bool strict, return -EDOM; return 0; } + +/** + * Add a new rule to the specified filter + * @param db the seccomp filter db + * @param strict the strict flag + * @param action the filter action + * @param syscall the syscall number + * @param chain_len the number of argument filters in the argument filter chain + * @param chain the argument filter chain + * + * This function adds a new argument/comparison/value to the seccomp filter for + * a syscall; multiple arguments can be specified and they will be chained + * together (essentially AND'd together) in the filter. When the strict flag + * is true the function will fail if the exact rule can not be added to the + * filter, if the strict flag is false the function will not fail if the + * function needs to adjust the rule due to architecture specifics. Returns + * zero on success, negative values on failure. + * + */ +int arch_filter_rule_add(struct db_filter *db, bool strict, + uint32_t action, int syscall, + unsigned int chain_len, struct db_api_arg *chain) +{ + int rc; + size_t chain_size = sizeof(*chain) * chain_len; + struct db_api_rule_list *rule, *rule_tail; + + /* ensure we aren't using any reserved syscall values */ + if (syscall < 0 && syscall > -100) + return -EINVAL; + + /* copy of the chain for each filter in the collection */ + rule = malloc(sizeof(*rule)); + if (rule == NULL) + return -ENOMEM; + rule->args = malloc(chain_size); + if (rule->args == NULL) { + free(rule); + return -ENOMEM; + } + rule->action = action; + rule->syscall = syscall; + rule->args_cnt = chain_len; + memcpy(rule->args, chain, chain_size); + rule->prev = NULL; + rule->next = NULL; + + /* add the new rule to the existing filter */ + if (db->arch->rule_add == NULL) { + rc = arch_syscall_translate(db->arch, &rule->syscall); + if (rc < 0) + goto rule_add_failure; + + /* if this is a pseudo syscall (syscall < 0) then we need to + * rewrite the rule for some arch specific reason */ + if (rule->syscall < 0) { + /* mangle the private chain copy */ + rc = arch_filter_rewrite(db->arch, strict, rule); + if ((rc == -EDOM) && (!strict)) { + /* don't consider this a failure */ + rc = 0; + goto rule_add_failure; + } + if (rc < 0) + goto rule_add_failure; + } + + rc = db_rule_add(db, rule); + } else + rc = (db->arch->rule_add)(db, rule); + if (rc == 0) { + /* insert the chain to the end of the filter's rule list */ + rule_tail = rule; + while (rule_tail->next) + rule_tail = rule_tail->next; + if (db->rules != NULL) { + rule->prev = db->rules->prev; + rule_tail->next = db->rules; + db->rules->prev->next = rule; + db->rules->prev = rule_tail; + } else { + rule->prev = rule_tail; + rule_tail->next = rule; + db->rules = rule; + } + } else + goto rule_add_failure; + + return 0; + +rule_add_failure: + do { + rule_tail = rule; + rule = rule->next; + free(rule_tail->args); + free(rule_tail); + } while (rule); + return rc; +} diff --git a/src/arch.h b/src/arch.h index c3ac524..54380f7 100644 --- a/src/arch.h +++ b/src/arch.h @@ -30,6 +30,8 @@ #include "system.h" +struct db_filter; +struct db_api_arg; struct db_api_rule_list; struct arch_def { @@ -52,6 +54,8 @@ struct arch_def { const char *(*syscall_resolve_num)(int num); int (*syscall_rewrite)(int *syscall); int (*filter_rewrite)(bool strict, struct db_api_rule_list *rule); + int (*rule_add)(struct db_filter *filter, + struct db_api_rule_list *rule); }; /* arch_def for the current architecture */ @@ -99,7 +103,8 @@ 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, - struct db_api_rule_list *rule); +int arch_filter_rule_add(struct db_filter *db, bool strict, + uint32_t action, int syscall, + unsigned int chain_len, struct db_api_arg *chain); #endif diff --git a/src/db.c b/src/db.c index 321a064..793a1db 100644 --- a/src/db.c +++ b/src/db.c @@ -1229,8 +1229,7 @@ gen_32_failure: * filter DB. Returns zero on success, negative values on failure. * */ -static int _db_rule_add(struct db_filter *db, - const struct db_api_rule_list *rule) +int db_rule_add(struct db_filter *db, const struct db_api_rule_list *rule) { int rc = -ENOMEM; int syscall = rule->syscall; @@ -1568,9 +1567,7 @@ int db_col_rule_add(struct db_filter_col *col, unsigned int chain_len; unsigned int arg_num; size_t chain_size; - struct db_filter *filter; 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 */ @@ -1614,67 +1611,9 @@ int db_col_rule_add(struct db_filter_col *col, } for (iter = 0; iter < col->filter_cnt; iter++) { - filter = col->filters[iter]; - - /* 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 (rule->syscall < 0) { - /* mangle the private chain copy */ - rc_tmp = arch_filter_rewrite(filter->arch, strict, - rule); - if (rc_tmp < 0) { - 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, 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: + rc_tmp = arch_filter_rule_add(col->filters[iter], strict, + action, syscall, + chain_len, chain); if (rc == 0 && rc_tmp < 0) rc = rc_tmp; } @@ -1755,7 +1694,7 @@ int db_col_transaction_start(struct db_filter_col *col) } /* insert the rule into the filter */ - if (_db_rule_add(filter_s, rule_o) != 0) + if (db_rule_add(filter_s, rule_o) != 0) goto trans_start_failure; /* next rule */ diff --git a/src/db.h b/src/db.h index 02e9394..6e1202e 100644 --- a/src/db.h +++ b/src/db.h @@ -219,4 +219,6 @@ int db_col_transaction_start(struct db_filter_col *col); void db_col_transaction_abort(struct db_filter_col *col); void db_col_transaction_commit(struct db_filter_col *col); +int db_rule_add(struct db_filter *db, const struct db_api_rule_list *rule); + #endif -- cgit v1.2.1