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]>
---
 include/seccomp.h |   73 +++++++++++++++++++++++++++++++++++
 src/api.c         |   76 +++++++++++++++++++++++++++++++++++++
 src/arch.c        |   45 ++++++++++++++++++++--
 src/arch.h        |    4 ++
 src/db.c          |  110 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/db.h          |    5 ++
 6 files changed, 306 insertions(+), 7 deletions(-)

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);


------------------------------------------------------------------------------
Got visibility?
Most devs has no idea what their production app looks like.
Find out how fast your code is with AppDynamics Lite.
http://ad.doubleclick.net/clk;262219671;13503038;y?
http://info.appdynamics.com/FreeJavaPerformanceDownload.html
_______________________________________________
libseccomp-discuss mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libseccomp-discuss

Reply via email to