summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Moore <pmoore@redhat.com>2012-09-24 12:28:59 -0400
committerPaul Moore <pmoore@redhat.com>2012-11-12 15:55:41 -0500
commit36d66f496ff6038668f55f4fb14d17c62b88c6ba (patch)
tree321f42617eec336f1d9be78a5c252798d53377f4
parent7aa8b04333cafc2117f44eb4babbb07eea26966a (diff)
downloadlibseccomp-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.h73
-rw-r--r--src/api.c76
-rw-r--r--src/arch.c45
-rw-r--r--src/arch.h4
-rw-r--r--src/db.c110
-rw-r--r--src/db.h5
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
*
diff --git a/src/api.c b/src/api.c
index 7fe1a9a..cf61982 100644
--- a/src/api.c
+++ b/src/api.c
@@ -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;
diff --git a/src/arch.c b/src/arch.c
index 8ab3c0a..a82f33f 100644
--- a/src/arch.c
+++ b/src/arch.c
@@ -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;
diff --git a/src/arch.h b/src/arch.h
index 43ef19f..ada353d 100644
--- a/src/arch.h
+++ b/src/arch.h
@@ -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);
/**
diff --git a/src/db.c b/src/db.c
index 174c95c..3a82e1c 100644
--- a/src/db.c
+++ b/src/db.c
@@ -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
diff --git a/src/db.h b/src/db.h
index a9ebbc9..61cac1d 100644
--- a/src/db.h
+++ b/src/db.h
@@ -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);