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 <[email protected]>
---
 0 files changed

diff --git a/include/seccomp.h b/include/seccomp.h
index f6cffea..0e5b31b 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);


------------------------------------------------------------------------------
Don't let slow site performance ruin your business. Deploy New Relic APM
Deploy New Relic app performance management and know exactly
what is happening inside your Ruby, Python, PHP, Java, and .NET app
Try New Relic at no cost today and get our sweet Data Nerd shirt too!
http://p.sf.net/sfu/newrelic-dev2dev
_______________________________________________
libseccomp-discuss mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libseccomp-discuss

Reply via email to