diff options
author | Paul Moore <pmoore@redhat.com> | 2012-09-24 12:28:59 -0400 |
---|---|---|
committer | Paul Moore <pmoore@redhat.com> | 2012-11-12 15:55:41 -0500 |
commit | 36d66f496ff6038668f55f4fb14d17c62b88c6ba (patch) | |
tree | 321f42617eec336f1d9be78a5c252798d53377f4 | |
parent | 7aa8b04333cafc2117f44eb4babbb07eea26966a (diff) | |
download | libseccomp-36d66f496ff6038668f55f4fb14d17c62b88c6ba.tar.gz |
api: add support for multiple architectures
Add the seccomp_arch_add() and seccomp_arch_remove() functions to add
and remove architectures from the filter. This patch also adds the
seccomp_merge() function which merges two filter contexts together
assuming there is no architecture conflicts.
Signed-off-by: Paul Moore <pmoore@redhat.com>
-rw-r--r-- | include/seccomp.h | 73 | ||||
-rw-r--r-- | src/api.c | 76 | ||||
-rw-r--r-- | src/arch.c | 45 | ||||
-rw-r--r-- | src/arch.h | 4 | ||||
-rw-r--r-- | src/db.c | 110 | ||||
-rw-r--r-- | src/db.h | 5 |
6 files changed, 306 insertions, 7 deletions
diff --git a/include/seccomp.h b/include/seccomp.h index e9a09ef..67d342e 100644 --- a/include/seccomp.h +++ b/include/seccomp.h @@ -24,6 +24,7 @@ #include <inttypes.h> #include <asm/unistd.h> +#include <linux/audit.h> #ifdef __cplusplus extern "C" { @@ -84,6 +85,21 @@ struct scmp_arg_cmp { */ /** + * The native architecture token + */ +#define SCMP_ARCH_NATIVE 0 + +/** + * The x86 (32-bit) architecture token + */ +#define SCMP_ARCH_X86 AUDIT_ARCH_I386 + +/** + * The x86-64 (64-bit) architecture token + */ +#define SCMP_ARCH_X86_64 AUDIT_ARCH_X86_64 + +/** * Convert a syscall name into the associated syscall number * @param x the syscall name */ @@ -194,6 +210,63 @@ int seccomp_reset(scmp_filter_ctx ctx, uint32_t def_action); void seccomp_release(scmp_filter_ctx ctx); /** + * Merge two filters + * @param ctx_dst the destination filter context + * @param ctx_src the source filter context + * + * This function merges two filter contexts into a single filter context and + * destroys the second filter context. The two filter contexts must have the + * same attribute values and not contain any of the same architectures; if they + * do, the merge operation will fail. On success, the source filter context + * will be destroyed and should no longer be used; it is not necessary to + * call seccomp_release() on the source filter context. Returns zero on + * success, negative values on failure. + * + */ +int seccomp_merge(scmp_filter_ctx ctx_dst, scmp_filter_ctx ctx_src); + +/** + * Check to see if an existing architecture is present in the filter + * @param ctx the filter context + * @param arch_token the architecture token, e.g. SCMP_ARCH_* + * + * This function tests to see if a given architecture is included in the filter + * context. If the architecture token is SCMP_ARCH_NATIVE then the native + * architecture will be assumed. Returns zero if the architecture exists in + * the filter, -EEXIST if it is not present, and other negative values on + * failure. + * + */ +int seccomp_arch_exist(const scmp_filter_ctx ctx, uint32_t arch_token); + +/** + * Adds an architecture to the filter + * @param ctx the filter context + * @param arch_token the architecture token, e.g. SCMP_ARCH_* + * + * This function adds a new architecture to the given seccomp filter context. + * Any new rules added after this function successfully returns will be added + * to this architecture but existing rules will not be added to this + * architecture. If the architecture token is SCMP_ARCH_NATIVE then the native + * architecture will be assumed. Returns zero on success, negative values on + * failure. + * + */ +int seccomp_arch_add(scmp_filter_ctx ctx, uint32_t arch_token); + +/** + * Removes an architecture from the filter + * @param ctx the filter context + * @param arch_token the architecture token, e.g. SCMP_ARCH_* + * + * This function removes an architecture from the given seccomp filter context. + * If the architecture token is SCMP_ARCH_NATIVE then the native architecture + * will be assumed. Returns zero on success, negative values on failure. + * + */ +int seccomp_arch_remove(scmp_filter_ctx ctx, uint32_t arch_token); + +/** * Loads the filter into the kernel * @param ctx the filter context * @@ -124,6 +124,82 @@ void seccomp_release(scmp_filter_ctx ctx) } /* NOTE - function header comment in include/seccomp.h */ +int seccomp_merge(scmp_filter_ctx ctx_dst, scmp_filter_ctx ctx_src) +{ + struct db_filter_col *col_dst = (struct db_filter_col *)ctx_dst; + struct db_filter_col *col_src = (struct db_filter_col *)ctx_src; + + if (db_col_valid(col_dst) || db_col_valid(col_src)) + return -EINVAL; + + /* NOTE: only the default action and NNP settings must match */ + if ((col_dst->attr.act_default != col_src->attr.act_default) || + (col_dst->attr.nnp_enable != col_src->attr.nnp_enable)) + return -EINVAL; + + return db_col_merge(col_dst, col_src); +} + +/* NOTE - function header comment in include/seccomp.h */ +int seccomp_arch_exist(const scmp_filter_ctx ctx, uint32_t arch_token) +{ + struct db_filter_col *col = (struct db_filter_col *)ctx; + + if (arch_token == 0) + arch_token = arch_def_native.token; + + if (arch_valid(arch_token)) + return -EINVAL; + + return (db_col_arch_exist(col, arch_token) ? 0 : -EEXIST); +} + +/* NOTE - function header comment in include/seccomp.h */ +int seccomp_arch_add(scmp_filter_ctx ctx, uint32_t arch_token) +{ + int rc; + const struct arch_def *arch; + struct db_filter *db; + struct db_filter_col *col = (struct db_filter_col *)ctx; + + if (arch_token == 0) + arch_token = arch_def_native.token; + + if (arch_valid(arch_token)) + return -EINVAL; + if (db_col_arch_exist(col, arch_token)) + return -EEXIST; + + arch = arch_def_lookup(arch_token); + if (arch == NULL) + return -EFAULT; + db = db_init(arch); + if (db == NULL) + return -ENOMEM; + rc = db_col_db_add(col, db); + if (rc < 0) + db_release(db); + + return rc; +} + +/* NOTE - function header comment in include/seccomp.h */ +int seccomp_arch_remove(scmp_filter_ctx ctx, uint32_t arch_token) +{ + struct db_filter_col *col = (struct db_filter_col *)ctx; + + if (arch_token == 0) + arch_token = arch_def_native.token; + + if (arch_valid(arch_token)) + return -EINVAL; + if (db_col_arch_exist(col, arch_token) != -EEXIST) + return -EEXIST; + + return db_col_db_remove(col, arch_token); +} + +/* NOTE - function header comment in include/seccomp.h */ int seccomp_load(const scmp_filter_ctx ctx) { int rc; @@ -59,13 +59,31 @@ const struct arch_def arch_def_native = { }; /** + * Validate the architecture token + * @param arch the architecture token + * + * Verify the given architecture token; return zero if valid, -EINVAL if not. + * + */ +int arch_valid(uint32_t arch) +{ + switch (arch) { + case AUDIT_ARCH_I386: + case AUDIT_ARCH_X86_64: + return 0; + } + + return -EINVAL; +} + +/** * Lookup the syscall table for an architecture * @param token the architecure token * * Return the architecture's syscall table, returns NULL on failure. * */ -const struct arch_syscall_def *_arch_def_lookup(uint32_t token) +static const struct arch_syscall_def *_arch_syscall_lookup(uint32_t token) { switch (token) { case AUDIT_ARCH_I386: @@ -80,6 +98,27 @@ const struct arch_syscall_def *_arch_def_lookup(uint32_t token) } /** + * Lookup the architecture definition + * @param token the architecure token + * + * Return the matching architecture definition, returns NULL on failure. + * + */ +const struct arch_def *arch_def_lookup(uint32_t token) +{ + switch (token) { + case AUDIT_ARCH_I386: + return &arch_def_i386; + break; + case AUDIT_ARCH_X86_64: + return &arch_def_x86_64; + break; + } + + return NULL; +} + +/** * Determine the maximum number of syscall arguments * @param arch the architecture definition * @@ -154,7 +193,7 @@ int arch_syscall_resolve_name(const struct arch_def *arch, const char *name) unsigned int iter; const struct arch_syscall_def *table; - table = _arch_def_lookup(arch->token); + table = _arch_syscall_lookup(arch->token); if (table == NULL) return __NR_SCMP_ERROR; @@ -182,7 +221,7 @@ const char *arch_syscall_resolve_num(const struct arch_def *arch, int num) unsigned int iter; const struct arch_syscall_def *table; - table = _arch_def_lookup(arch->token); + table = _arch_syscall_lookup(arch->token); if (table == NULL) return NULL; @@ -73,6 +73,10 @@ struct arch_syscall_def { #define ARG_COUNT_MAX 6 +int arch_valid(uint32_t arch); + +const struct arch_def *arch_def_lookup(uint32_t token); + int arch_arg_count_max(const struct arch_def *arch); /** @@ -404,6 +404,72 @@ int db_col_valid(struct db_filter_col *col) } /** + * Merge two filter collections + * @param col_dst the destination filter collection + * @param col_src the source filter collection + * + * This function merges two filter collections into the given destination + * collection. The source filter collection is no longer valid if the function + * returns successfully. Returns zero on success, negative values on failure. + * + */ +int db_col_merge(struct db_filter_col *col_dst, struct db_filter_col *col_src) +{ + unsigned int iter_a, iter_b; + struct db_filter **dbs; + + /* make sure we don't have any arch/filter collisions */ + for (iter_a = 0; iter_a < col_dst->filter_cnt; iter_a++) { + for (iter_b = 0; iter_b < col_src->filter_cnt; iter_b++) { + if (col_dst->filters[iter_a]->arch->token == + col_src->filters[iter_b]->arch->token) + return -EEXIST; + } + } + + /* expand the destination */ + dbs = realloc(col_dst->filters, + sizeof(struct db_filter *) * + (col_dst->filter_cnt + col_src->filter_cnt)); + if (dbs == NULL) + return -ENOMEM; + + /* transfer the architecture filters */ + for (iter_a = col_dst->filter_cnt, iter_b = 0; + iter_b < col_src->filter_cnt; iter_a++, iter_b++) { + col_dst->filters[iter_a] = col_src->filters[iter_b]; + col_dst->filter_cnt++; + } + + /* free the source */ + col_src->filter_cnt = 0; + db_col_release(col_src); + + return 0; +} + +/** + * Check to see if an architecture filter exists in the filter collection + * @param col the seccomp filter collection + * @param arch_token the architecture token + * + * Iterate through the given filter collection checking to see if a filter + * exists for the specified architecture. Returns -EEXIST if a filter is found, + * zero if a matching filter does not exist. + * + */ +int db_col_arch_exist(struct db_filter_col *col, uint32_t arch_token) +{ + unsigned int iter; + + for (iter = 0; iter < col->filter_cnt; iter++) + if (col->filters[iter]->arch->token == arch_token) + return -EEXIST; + + return 0; +} + +/** * Get a filter attribute * @param col the seccomp filter collection * @param attr the filter attribute @@ -481,12 +547,10 @@ int db_col_attr_set(struct db_filter_col *col, */ int db_col_db_add(struct db_filter_col *col, struct db_filter *db) { - unsigned int iter; struct db_filter **dbs; - for (iter = 0; iter < col->filter_cnt; iter++) - if (col->filters[iter]->arch->token == db->arch->token) - return -EEXIST; + if (db_col_arch_exist(col, db->arch->token)) + return -EEXIST; dbs = realloc(col->filters, sizeof(struct db_filter *) * (col->filter_cnt + 1)); @@ -500,6 +564,44 @@ int db_col_db_add(struct db_filter_col *col, struct db_filter *db) } /** + * Remove a filter DB from a filter collection + * @param col the seccomp filter collection + * @param arch_token the architecture token + * + * This function removes an existing seccomp filter DB from an existing seccomp + * filter collection. Returns zero on success, negative values on failure. + * + */ +int db_col_db_remove(struct db_filter_col *col, uint32_t arch_token) +{ + unsigned int iter; + unsigned int found; + struct db_filter **dbs; + + if ((col->filter_cnt <= 1) || (db_col_arch_exist(col, arch_token) == 0)) + return -EINVAL; + + for (found = 0, iter = 0; iter < col->filter_cnt; iter++) { + if (found) + col->filters[iter - 1] = col->filters[iter]; + else if (col->filters[iter]->arch->token == arch_token) { + db_release(col->filters[iter]); + found = 1; + } + } + col->filters[--col->filter_cnt] = NULL; + + /* NOTE: if we can't do the realloc it isn't fatal, we just have some + * extra space that will get cleaned up later */ + dbs = realloc(col->filters, + sizeof(struct db_filter *) * col->filter_cnt); + if (dbs != NULL) + col->filters = dbs; + + return 0; +} + +/** * Free and reset the seccomp filter DB * @param db the seccomp filter DB * @param def_action the default filter action @@ -170,12 +170,17 @@ void db_col_release(struct db_filter_col *col); int db_col_valid(struct db_filter_col *col); +int db_col_merge(struct db_filter_col *col_dst, struct db_filter_col *col_src); + +int db_col_arch_exist(struct db_filter_col *col, uint32_t arch_token); + int db_col_attr_get(const struct db_filter_col *col, enum scmp_filter_attr attr, uint32_t *value); int db_col_attr_set(struct db_filter_col *col, enum scmp_filter_attr attr, uint32_t value); int db_col_db_add(struct db_filter_col *col, struct db_filter *db); +int db_col_db_remove(struct db_filter_col *col, uint32_t arch_token); struct db_filter *db_init(const struct arch_def *arch); void db_reset(struct db_filter *db); |