Upgrade libseccomp to 2.3.3 from 2.3.1
[linux-seccomp.git] / libseccomp / src / db.c
diff --git a/libseccomp/src/db.c b/libseccomp/src/db.c
deleted file mode 100644 (file)
index 1a85b1f..0000000
+++ /dev/null
@@ -1,1766 +0,0 @@
-/**
- * Enhanced Seccomp Filter DB
- *
- * Copyright (c) 2012,2016 Red Hat <pmoore@redhat.com>
- * Author: Paul Moore <paul@paul-moore.com>
- */
-
-/*
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of version 2.1 of the GNU Lesser General Public License as
- * published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this library; if not, see <http://www.gnu.org/licenses>.
- */
-
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-
-#include <seccomp.h>
-
-#include "arch.h"
-#include "db.h"
-#include "system.h"
-
-/* state values */
-#define _DB_STA_VALID                  0xA1B2C3D4
-#define _DB_STA_FREED                  0x1A2B3C4D
-
-/* the priority field is fairly simple - without any user hints, or in the case
- * of a hint "tie", we give higher priority to syscalls with less chain nodes
- * (filter is easier to evaluate) */
-#define _DB_PRI_MASK_CHAIN             0x0000FFFF
-#define _DB_PRI_MASK_USER              0x00FF0000
-#define _DB_PRI_USER(x)                        (((x) << 16) & _DB_PRI_MASK_USER)
-
-/* private structure for tracking the state of the sub-tree "pruning" */
-struct db_prune_state {
-       bool prefix_exist;
-       bool prefix_new;
-       bool matched;
-};
-
-static unsigned int _db_tree_free(struct db_arg_chain_tree *tree);
-
-/**
- * Do not call this function directly, use _db_tree_free() instead
- */
-static unsigned int __db_tree_free(struct db_arg_chain_tree *tree)
-{
-       int cnt;
-
-       if (tree == NULL || --(tree->refcnt) > 0)
-               return 0;
-
-       /* we assume the caller has ensured that 'tree->lvl_prv == NULL' */
-       cnt = __db_tree_free(tree->lvl_nxt);
-       cnt += _db_tree_free(tree->nxt_t);
-       cnt += _db_tree_free(tree->nxt_f);
-
-       free(tree);
-       return cnt + 1;
-}
-
-/**
- * Free a syscall filter argument chain tree
- * @param tree the argument chain list
- *
- * This function frees a tree and returns the number of nodes freed.
- *
- */
-static unsigned int _db_tree_free(struct db_arg_chain_tree *tree)
-{
-       struct db_arg_chain_tree *iter;
-
-       if (tree == NULL)
-               return 0;
-
-       iter = tree;
-       while (iter->lvl_prv != NULL)
-               iter = iter->lvl_prv;
-
-       return __db_tree_free(iter);
-}
-
-/**
- * Remove a node from an argument chain tree
- * @param tree the pointer to the tree
- * @param node the node to remove
- *
- * This function searches the tree looking for the node and removes it once
- * found.  Returns the number of nodes freed.
- *
- */
-static unsigned int _db_tree_remove(struct db_arg_chain_tree **tree,
-                                   struct db_arg_chain_tree *node)
-{
-       int cnt = 0;
-       struct db_arg_chain_tree *c_iter;
-
-       if (tree == NULL || *tree == NULL || node == NULL)
-               return 0;
-
-       c_iter = *tree;
-       while (c_iter->lvl_prv != NULL)
-               c_iter = c_iter->lvl_prv;
-
-       do {
-               if (c_iter == node || db_chain_zombie(c_iter)) {
-                       /* remove from the tree */
-                       if (c_iter == *tree) {
-                               if (c_iter->lvl_prv != NULL)
-                                       *tree = c_iter->lvl_prv;
-                               else
-                                       *tree = c_iter->lvl_nxt;
-                       }
-                       if (c_iter->lvl_prv != NULL)
-                               c_iter->lvl_prv->lvl_nxt = c_iter->lvl_nxt;
-                       if (c_iter->lvl_nxt != NULL)
-                               c_iter->lvl_nxt->lvl_prv = c_iter->lvl_prv;
-
-                       /* free and return */
-                       c_iter->lvl_prv = NULL;
-                       c_iter->lvl_nxt = NULL;
-                       cnt += _db_tree_free(c_iter);
-                       return cnt;
-               }
-
-               /* check the true/false sub-trees */
-               cnt += _db_tree_remove(&(c_iter->nxt_t), node);
-               cnt += _db_tree_remove(&(c_iter->nxt_f), node);
-
-               c_iter = c_iter->lvl_nxt;
-       } while (c_iter != NULL);
-
-       return cnt;
-}
-
-/**
- * Traverse a tree checking the action values
- * @param tree the pointer to the tree
- * @param action the action
- *
- * Traverse the tree inspecting each action to see if it matches the given
- * action.  Returns zero if all actions match the given action, negative values
- * on failure.
- *
- */
-static int _db_tree_act_check(struct db_arg_chain_tree *tree, uint32_t action)
-{
-       int rc;
-       struct db_arg_chain_tree *c_iter;
-
-       if (tree == NULL)
-               return 0;
-
-       c_iter = tree;
-       while (c_iter->lvl_prv != NULL)
-               c_iter = c_iter->lvl_prv;
-
-       do {
-               if (c_iter->act_t_flg && c_iter->act_t != action)
-                       return -EEXIST;
-               if (c_iter->act_f_flg && c_iter->act_f != action)
-                       return -EEXIST;
-
-               rc = _db_tree_act_check(c_iter->nxt_t, action);
-               if (rc < 0)
-                       return rc;
-               rc = _db_tree_act_check(c_iter->nxt_f, action);
-               if (rc < 0)
-                       return rc;
-
-               c_iter = c_iter->lvl_nxt;
-       } while (c_iter != NULL);
-
-       return 0;
-}
-
-/**
- * Checks for a sub-tree match in an existing tree and prunes the tree
- * @param prev the head of the existing tree or sub-tree
- * @param existing the starting point into the existing tree
- * @param new pointer to the new tree
- * @param state pointer to the pruning state
- *
- * This function searches the existing and new trees trying to prune each to
- * eliminate redundancy.  Returns the number of nodes removed from the tree on
- * success, zero if no changes were made, and negative values if the new tree
- * should be discarded.
- *
- */
-static int _db_tree_sub_prune(struct db_arg_chain_tree **prev,
-                             struct db_arg_chain_tree *existing,
-                             struct db_arg_chain_tree *new,
-                             struct db_prune_state *state)
-{
-       int rc = 0;
-       int rc_tmp;
-       struct db_arg_chain_tree *ec_iter;
-       struct db_arg_chain_tree *ec_iter_tmp;
-       struct db_arg_chain_tree *c_iter;
-       struct db_prune_state state_new;
-
-       if (!state || !existing || !new)
-               return 0;
-
-       ec_iter = existing;
-       c_iter = new;
-       do {
-               if (db_chain_eq(ec_iter, c_iter)) {
-                       /* equal */
-
-                       if (db_chain_leaf(c_iter)) {
-                               /* leaf */
-                               if (db_chain_eq_result(ec_iter, c_iter)) {
-                                       /* identical results */
-                                       if (prev != NULL)
-                                               return _db_tree_remove(prev,
-                                                                      ec_iter);
-                                       else
-                                               return -1;
-                               }
-                               if (c_iter->act_t_flg && ec_iter->nxt_t) {
-                                       /* new is shorter (true) */
-                                       if (prev == NULL)
-                                               return -1;
-                                       rc += _db_tree_remove(&(ec_iter->nxt_t),
-                                                             ec_iter->nxt_t);
-                                       ec_iter->act_t = c_iter->act_t;
-                                       ec_iter->act_t_flg = true;
-                               }
-                               if (c_iter->act_f_flg && ec_iter->nxt_f) {
-                                       /* new is shorter (false) */
-                                       if (prev == NULL)
-                                               return -1;
-                                       rc += _db_tree_remove(&(ec_iter->nxt_f),
-                                                             ec_iter->nxt_f);
-                                       ec_iter->act_f = c_iter->act_f;
-                                       ec_iter->act_f_flg = true;
-                               }
-
-                               return rc;
-                       }
-
-                       if (c_iter->nxt_t && ec_iter->act_t_flg)
-                               /* existing is shorter (true) */
-                               return -1;
-                       if (c_iter->nxt_f && ec_iter->act_f_flg)
-                               /* existing is shorter (false) */
-                               return -1;
-
-                       if (c_iter->nxt_t) {
-                               state_new = *state;
-                               state_new.matched = true;
-                               rc_tmp = _db_tree_sub_prune((prev ?
-                                                            &ec_iter : NULL),
-                                                           ec_iter->nxt_t,
-                                                           c_iter->nxt_t,
-                                                           &state_new);
-                               rc += (rc_tmp > 0 ? rc_tmp : 0);
-                               if (state->prefix_new && rc_tmp < 0)
-                                       return (rc > 0 ? rc : rc_tmp);
-                       }
-                       if (c_iter->nxt_f) {
-                               state_new = *state;
-                               state_new.matched = true;
-                               rc_tmp = _db_tree_sub_prune((prev ?
-                                                            &ec_iter : NULL),
-                                                           ec_iter->nxt_f,
-                                                           c_iter->nxt_f,
-                                                           &state_new);
-                               rc += (rc_tmp > 0 ? rc_tmp : 0);
-                               if (state->prefix_new && rc_tmp < 0)
-                                       return (rc > 0 ? rc : rc_tmp);
-                       }
-               } else if (db_chain_lt(ec_iter, c_iter)) {
-                       /* less than */
-                       if (state->matched || state->prefix_new)
-                               goto next;
-                       state_new = *state;
-                       state_new.prefix_exist = true;
-
-                       if (ec_iter->nxt_t) {
-                               rc_tmp = _db_tree_sub_prune((prev ?
-                                                            &ec_iter : NULL),
-                                                           ec_iter->nxt_t,
-                                                           c_iter,
-                                                           &state_new);
-                               rc += (rc_tmp > 0 ? rc_tmp : 0);
-                       }
-                       if (ec_iter->nxt_f) {
-                               rc_tmp = _db_tree_sub_prune((prev ?
-                                                            &ec_iter : NULL),
-                                                           ec_iter->nxt_f,
-                                                           c_iter,
-                                                           &state_new);
-                               rc += (rc_tmp > 0 ? rc_tmp : 0);
-                       }
-               } else if (db_chain_gt(ec_iter, c_iter)) {
-                       /* greater than */
-                       if (state->matched || state->prefix_exist)
-                               goto next;
-                       state_new = *state;
-                       state_new.prefix_new = true;
-
-                       if (c_iter->nxt_t) {
-                               rc_tmp = _db_tree_sub_prune(NULL,
-                                                           ec_iter,
-                                                           c_iter->nxt_t,
-                                                           &state_new);
-                               rc += (rc_tmp > 0 ? rc_tmp : 0);
-                               if (rc_tmp < 0)
-                                       return (rc > 0 ? rc : rc_tmp);
-                       }
-                       if (c_iter->nxt_f) {
-                               rc_tmp = _db_tree_sub_prune(NULL,
-                                                           ec_iter,
-                                                           c_iter->nxt_f,
-                                                           &state_new);
-                               rc += (rc_tmp > 0 ? rc_tmp : 0);
-                               if (rc_tmp < 0)
-                                       return (rc > 0 ? rc : rc_tmp);
-                       }
-               }
-
-next:
-               /* re-check current node and advance to the next node */
-               if (db_chain_zombie(ec_iter)) {
-                       ec_iter_tmp = ec_iter->lvl_nxt;
-                       rc += _db_tree_remove(prev, ec_iter);
-                       ec_iter = ec_iter_tmp;
-               } else
-                       ec_iter = ec_iter->lvl_nxt;
-       } while (ec_iter);
-
-       return rc;
-}
-
-/**
- * Free and reset the seccomp filter DB
- * @param db the seccomp filter DB
- *
- * This function frees any existing filters and resets the filter DB to a
- * default state; only the DB architecture is preserved.
- *
- */
-static void _db_reset(struct db_filter *db)
-{
-       struct db_sys_list *s_iter;
-       struct db_api_rule_list *r_iter;
-
-       if (db == NULL)
-               return;
-
-       /* free any filters */
-       if (db->syscalls != NULL) {
-               s_iter = db->syscalls;
-               while (s_iter != NULL) {
-                       db->syscalls = s_iter->next;
-                       _db_tree_free(s_iter->chains);
-                       free(s_iter);
-                       s_iter = db->syscalls;
-               }
-               db->syscalls = NULL;
-       }
-
-       /* free any rules */
-       if (db->rules != NULL) {
-               /* split the loop first then loop and free */
-               db->rules->prev->next = NULL;
-               r_iter = db->rules;
-               while (r_iter != NULL) {
-                       db->rules = r_iter->next;
-                       free(r_iter->args);
-                       free(r_iter);
-                       r_iter = db->rules;
-               }
-               db->rules = NULL;
-       }
-}
-
-/**
- * Intitalize a seccomp filter DB
- * @param arch the architecture definition
- *
- * This function initializes a seccomp filter DB and readies it for use.
- * Returns a pointer to the DB on success, NULL on failure.
- *
- */
-static struct db_filter *_db_init(const struct arch_def *arch)
-{
-       struct db_filter *db;
-
-       db = malloc(sizeof(*db));
-       if (db == NULL)
-               return NULL;
-
-       /* clear the buffer for the first time and set the arch */
-       memset(db, 0, sizeof(*db));
-       db->arch = arch;
-
-       /* reset the DB to a known state */
-       _db_reset(db);
-
-       return db;
-}
-
-/**
- * Destroy a seccomp filter DB
- * @param db the seccomp filter DB
- *
- * This function destroys a seccomp filter DB.  After calling this function,
- * the filter should no longer be referenced.
- *
- */
-static void _db_release(struct db_filter *db)
-{
-       if (db == NULL)
-               return;
-
-       /* free and reset the DB */
-       _db_reset(db);
-       free(db);
-}
-
-/**
- * Destroy a seccomp filter snapshot
- * @param snap the seccomp filter snapshot
- *
- * This function destroys a seccomp filter snapshot.  After calling this
- * function, the snapshot should no longer be referenced.
- *
- */
-static void _db_snap_release(struct db_filter_snap *snap)
-{
-       unsigned int iter;
-
-       if (snap->filter_cnt > 0) {
-               for (iter = 0; iter < snap->filter_cnt; iter++) {
-                       if (snap->filters[iter])
-                               _db_release(snap->filters[iter]);
-               }
-               free(snap->filters);
-       }
-       free(snap);
-}
-
-/**
- * Update the user specified portion of the syscall priority
- * @param db the seccomp filter db
- * @param syscall the syscall number
- * @param priority the syscall priority
- *
- * This function sets, or updates, the syscall priority; the highest priority
- * value between the existing and specified value becomes the new syscall
- * priority.  If the syscall entry does not already exist, a new phantom
- * syscall entry is created as a placeholder.  Returns zero on success,
- * negative values on failure.
- *
- */
-static int _db_syscall_priority(struct db_filter *db,
-                               int syscall, uint8_t priority)
-{
-       unsigned int sys_pri = _DB_PRI_USER(priority);
-       struct db_sys_list *s_new, *s_iter, *s_prev = NULL;
-
-       assert(db != NULL);
-
-       s_iter = db->syscalls;
-       while (s_iter != NULL && s_iter->num < syscall) {
-               s_prev = s_iter;
-               s_iter = s_iter->next;
-       }
-
-       /* matched an existing syscall entry */
-       if (s_iter != NULL && s_iter->num == syscall) {
-               if (sys_pri > (s_iter->priority & _DB_PRI_MASK_USER)) {
-                       s_iter->priority &= (~_DB_PRI_MASK_USER);
-                       s_iter->priority |= sys_pri;
-               }
-               return 0;
-       }
-
-       /* no existing syscall entry - create a phantom entry */
-       s_new = malloc(sizeof(*s_new));
-       if (s_new == NULL)
-               return -ENOMEM;
-       memset(s_new, 0, sizeof(*s_new));
-       s_new->num = syscall;
-       s_new->priority = sys_pri;
-       s_new->valid = false;
-
-       /* add it before s_iter */
-       if (s_prev != NULL) {
-               s_new->next = s_prev->next;
-               s_prev->next = s_new;
-       } else {
-               s_new->next = db->syscalls;
-               db->syscalls = s_new;
-       }
-
-       return 0;
-}
-
-/**
- * Free and reset the seccomp filter collection
- * @param col the seccomp filter collection
- * @param def_action the default filter action
- *
- * This function frees any existing filter DBs and resets the collection to a
- * default state.  In the case of failure the filter collection may be in an
- * unknown state and should be released.  Returns zero on success, negative
- * values on failure.
- *
- */
-int db_col_reset(struct db_filter_col *col, uint32_t def_action)
-{
-       unsigned int iter;
-       struct db_filter *db;
-       struct db_filter_snap *snap;
-
-       if (col == NULL)
-               return -EINVAL;
-
-       /* free any filters */
-       for (iter = 0; iter < col->filter_cnt; iter++)
-               _db_release(col->filters[iter]);
-       col->filter_cnt = 0;
-       if (col->filters)
-               free(col->filters);
-       col->filters = NULL;
-
-       /* set the endianess to undefined */
-       col->endian = 0;
-
-       /* set the default attribute values */
-       col->attr.act_default = def_action;
-       col->attr.act_badarch = SCMP_ACT_KILL;
-       col->attr.nnp_enable = 1;
-       col->attr.tsync_enable = 0;
-
-       /* set the state */
-       col->state = _DB_STA_VALID;
-
-       /* reset the initial db */
-       db = _db_init(arch_def_native);
-       if (db == NULL)
-               return -ENOMEM;
-       if (db_col_db_add(col, db) < 0) {
-               _db_release(db);
-               return -ENOMEM;
-       }
-
-       /* reset the transactions */
-       while (col->snapshots) {
-               snap = col->snapshots;
-               col->snapshots = snap->next;
-               for (iter = 0; iter < snap->filter_cnt; iter++)
-                       _db_release(snap->filters[iter]);
-               free(snap->filters);
-               free(snap);
-       }
-
-       return 0;
-}
-
-/**
- * Intitalize a seccomp filter collection
- * @param def_action the default filter action
- *
- * This function initializes a seccomp filter collection and readies it for
- * use.  Returns a pointer to the collection on success, NULL on failure.
- *
- */
-struct db_filter_col *db_col_init(uint32_t def_action)
-{
-       struct db_filter_col *col;
-
-       col = malloc(sizeof(*col));
-       if (col == NULL)
-               return NULL;
-
-       /* clear the buffer for the first time */
-       memset(col, 0, sizeof(*col));
-
-       /* reset the DB to a known state */
-       if (db_col_reset(col, def_action) < 0)
-               goto init_failure;
-
-       return col;
-
-init_failure:
-       db_col_release(col);
-       return NULL;
-}
-
-/**
- * Destroy a seccomp filter collection
- * @param col the seccomp filter collection
- *
- * This function destroys a seccomp filter collection.  After calling this
- * function, the filter should no longer be referenced.
- *
- */
-void db_col_release(struct db_filter_col *col)
-{
-       unsigned int iter;
-
-       if (col == NULL)
-               return;
-
-       /* set the state, just in case */
-       col->state = _DB_STA_FREED;
-
-       /* free any filters */
-       for (iter = 0; iter < col->filter_cnt; iter++)
-               _db_release(col->filters[iter]);
-       col->filter_cnt = 0;
-       if (col->filters)
-               free(col->filters);
-       col->filters = NULL;
-
-       /* free the collection */
-       free(col);
-}
-
-/**
- * Validate the seccomp action
- * @param action the seccomp action
- *
- * Verify that the given action is a valid seccomp action; return zero if
- * valid, -EINVAL if invalid.
- */
-int db_action_valid(uint32_t action)
-{
-       if (action == SCMP_ACT_KILL)
-               return 0;
-       else if (action == SCMP_ACT_TRAP)
-               return 0;
-       else if ((action == SCMP_ACT_ERRNO(action & 0x0000ffff)) &&
-                ((action & 0x0000ffff) < MAX_ERRNO))
-               return 0;
-       else if (action == SCMP_ACT_TRACE(action & 0x0000ffff))
-               return 0;
-       else if (action == SCMP_ACT_ALLOW)
-               return 0;
-
-       return -EINVAL;
-}
-
-/**
- * Validate a filter collection
- * @param col the seccomp filter collection
- *
- * This function validates a seccomp filter collection.  Returns zero if the
- * collection is valid, negative values on failure.
- *
- */
-int db_col_valid(struct db_filter_col *col)
-{
-       if (col != NULL && col->state == _DB_STA_VALID && col->filter_cnt > 0)
-               return 0;
-       return -EINVAL;
-}
-
-/**
- * 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;
-
-       /* verify that the endianess is a match */
-       if (col_dst->endian != col_src->endian)
-               return -EEXIST;
-
-       /* 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;
-       col_dst->filters = dbs;
-
-       /* 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
- * @param value the filter attribute value
- *
- * Get the requested filter attribute and provide it via @value.  Returns zero
- * on success, negative values on failure.
- *
- */
-int db_col_attr_get(const struct db_filter_col *col,
-                   enum scmp_filter_attr attr, uint32_t *value)
-{
-       int rc = 0;
-
-       switch (attr) {
-       case SCMP_FLTATR_ACT_DEFAULT:
-               *value = col->attr.act_default;
-               break;
-       case SCMP_FLTATR_ACT_BADARCH:
-               *value = col->attr.act_badarch;
-               break;
-       case SCMP_FLTATR_CTL_NNP:
-               *value = col->attr.nnp_enable;
-               break;
-       case SCMP_FLTATR_CTL_TSYNC:
-               *value = col->attr.tsync_enable;
-               break;
-       default:
-               rc = -EEXIST;
-               break;
-       }
-
-       return rc;
-}
-
-/**
- * Set a filter attribute
- * @param col the seccomp filter collection
- * @param attr the filter attribute
- * @param value the filter attribute value
- *
- * Set the requested filter attribute with the given value.  Returns zero on
- * success, negative values on failure.
- *
- */
-int db_col_attr_set(struct db_filter_col *col,
-                   enum scmp_filter_attr attr, uint32_t value)
-{
-       int rc = 0;
-
-       switch (attr) {
-       case SCMP_FLTATR_ACT_DEFAULT:
-               /* read only */
-               return -EACCES;
-               break;
-       case SCMP_FLTATR_ACT_BADARCH:
-               if (db_action_valid(value) == 0)
-                       col->attr.act_badarch = value;
-               else
-                       return -EINVAL;
-               break;
-       case SCMP_FLTATR_CTL_NNP:
-               col->attr.nnp_enable = (value ? 1 : 0);
-               break;
-       case SCMP_FLTATR_CTL_TSYNC:
-               rc = sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC);
-               if (rc == 1) {
-                       /* supported */
-                       rc = 0;
-                       col->attr.tsync_enable = (value ? 1 : 0);
-               } else if (rc == 0)
-                       /* unsupported */
-                       rc = -EOPNOTSUPP;
-               break;
-       default:
-               rc = -EEXIST;
-               break;
-       }
-
-       return rc;
-}
-
-/**
- * Add a new architecture filter to a filter collection
- * @param col the seccomp filter collection
- * @param arch the architecture
- *
- * This function adds a new architecture filter DB to an existing seccomp
- * filter collection assuming there isn't a filter DB already present with the
- * same architecture.  Returns zero on success, negative values on failure.
- *
- */
-int db_col_db_new(struct db_filter_col *col, const struct arch_def *arch)
-{
-       int rc;
-       struct db_filter *db;
-
-       db = _db_init(arch);
-       if (db == NULL)
-               return -ENOMEM;
-       rc = db_col_db_add(col, db);
-       if (rc < 0)
-               _db_release(db);
-
-       return rc;
-}
-
-/**
- * Add a new filter DB to a filter collection
- * @param col the seccomp filter collection
- * @param db the seccomp filter DB
- *
- * This function adds an existing seccomp filter DB to an existing seccomp
- * filter collection assuming there isn't a filter DB already present with the
- * same architecture.  Returns zero on success, negative values on failure.
- *
- */
-int db_col_db_add(struct db_filter_col *col, struct db_filter *db)
-{
-       struct db_filter **dbs;
-
-       if (col->endian != 0 && col->endian != db->arch->endian)
-               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));
-       if (dbs == NULL)
-               return -ENOMEM;
-       col->filters = dbs;
-       col->filter_cnt++;
-       col->filters[col->filter_cnt - 1] = db;
-       if (col->endian == 0)
-               col->endian = db->arch->endian;
-
-       return 0;
-}
-
-/**
- * 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 <= 0) || (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;
-
-       if (col->filter_cnt > 0) {
-               /* NOTE: if we can't do the realloc it isn't fatal, we just
-                *       have some extra space allocated */
-               dbs = realloc(col->filters,
-                             sizeof(struct db_filter *) * col->filter_cnt);
-               if (dbs != NULL)
-                       col->filters = dbs;
-       } else {
-               /* this was the last filter so free all the associated memory
-                * and reset the endian token */
-               free(col->filters);
-               col->filters = NULL;
-               col->endian = 0;
-       }
-
-       return 0;
-}
-
-/**
- * Test if the argument filter can be skipped because it's a tautology
- * @param arg argument filter
- *
- * If this argument filter applied to the lower 32 bit can be skipped this
- * function returns false.
- *
- */
-static bool _db_arg_cmp_need_lo(const struct db_api_arg *arg)
-{
-       if (arg->op == SCMP_CMP_MASKED_EQ && D64_LO(arg->mask) == 0)
-               return false;
-
-       return true;
-}
-
-/**
- * Test if the argument filter can be skipped because it's a tautology
- * @param arg argument filter
- *
- * If this argument filter applied to the upper 32 bit can be skipped this
- * function returns false.
- *
- */
-static bool _db_arg_cmp_need_hi(const struct db_api_arg *arg)
-{
-       if (arg->op == SCMP_CMP_MASKED_EQ && D64_HI(arg->mask) == 0)
-               return false;
-
-       return true;
-}
-
-/**
- * Fixup the node based on the op/mask
- * @param node the chain node
- *
- * Ensure the datum is masked as well.
- *
- */
-static void _db_node_mask_fixup(struct db_arg_chain_tree *node)
-{
-       node->datum &= node->mask;
-}
-
-/**
- * Generate a new filter rule for a 64 bit system
- * @param arch the architecture definition
- * @param action the filter action
- * @param syscall the syscall number
- * @param chain argument filter chain
- *
- * This function generates a new syscall filter for a 64 bit system. Returns
- * zero on success, negative values on failure.
- *
- */
-static struct db_sys_list *_db_rule_gen_64(const struct arch_def *arch,
-                                          uint32_t action,
-                                          unsigned int syscall,
-                                          struct db_api_arg *chain)
-{
-       unsigned int iter;
-       int chain_len_max;
-       struct db_sys_list *s_new;
-       struct db_arg_chain_tree *c_iter_hi = NULL, *c_iter_lo = NULL;
-       struct db_arg_chain_tree *c_prev_hi = NULL, *c_prev_lo = NULL;
-       bool tf_flag;
-
-       s_new = malloc(sizeof(*s_new));
-       if (s_new == NULL)
-               return NULL;
-       memset(s_new, 0, sizeof(*s_new));
-       s_new->num = syscall;
-       s_new->valid = true;
-       /* run through the argument chain */
-       chain_len_max = arch_arg_count_max(arch);
-       if (chain_len_max < 0)
-               goto gen_64_failure;
-       for (iter = 0; iter < chain_len_max; iter++) {
-               if (chain[iter].valid == 0)
-                       continue;
-
-               /* TODO: handle the case were either hi or lo isn't needed */
-
-               /* skip generating instruction which are no-ops */
-               if (!_db_arg_cmp_need_hi(&chain[iter]) &&
-                   !_db_arg_cmp_need_lo(&chain[iter]))
-                       continue;
-
-               c_iter_hi = malloc(sizeof(*c_iter_hi));
-               if (c_iter_hi == NULL)
-                       goto gen_64_failure;
-               memset(c_iter_hi, 0, sizeof(*c_iter_hi));
-               c_iter_hi->refcnt = 1;
-               c_iter_lo = malloc(sizeof(*c_iter_lo));
-               if (c_iter_lo == NULL) {
-                       free(c_iter_hi);
-                       goto gen_64_failure;
-               }
-               memset(c_iter_lo, 0, sizeof(*c_iter_lo));
-               c_iter_lo->refcnt = 1;
-
-               /* link this level to the previous level */
-               if (c_prev_lo != NULL) {
-                       if (!tf_flag) {
-                               c_prev_lo->nxt_f = c_iter_hi;
-                               c_prev_hi->nxt_f = c_iter_hi;
-                               c_iter_hi->refcnt++;
-                       } else
-                               c_prev_lo->nxt_t = c_iter_hi;
-               } else
-                       s_new->chains = c_iter_hi;
-               s_new->node_cnt += 2;
-
-               /* set the arg, op, and datum fields */
-               c_iter_hi->arg = chain[iter].arg;
-               c_iter_lo->arg = chain[iter].arg;
-               c_iter_hi->arg_offset = arch_arg_offset_hi(arch,
-                                                          c_iter_hi->arg);
-               c_iter_lo->arg_offset = arch_arg_offset_lo(arch,
-                                                          c_iter_lo->arg);
-               switch (chain[iter].op) {
-               case SCMP_CMP_GT:
-                       c_iter_hi->op = SCMP_CMP_GE;
-                       c_iter_lo->op = SCMP_CMP_GT;
-                       tf_flag = true;
-                       break;
-               case SCMP_CMP_NE:
-                       c_iter_hi->op = SCMP_CMP_EQ;
-                       c_iter_lo->op = SCMP_CMP_EQ;
-                       tf_flag = false;
-                       break;
-               case SCMP_CMP_LT:
-                       c_iter_hi->op = SCMP_CMP_GE;
-                       c_iter_lo->op = SCMP_CMP_GE;
-                       tf_flag = false;
-                       break;
-               case SCMP_CMP_LE:
-                       c_iter_hi->op = SCMP_CMP_GE;
-                       c_iter_lo->op = SCMP_CMP_GT;
-                       tf_flag = false;
-                       break;
-               default:
-                       c_iter_hi->op = chain[iter].op;
-                       c_iter_lo->op = chain[iter].op;
-                       tf_flag = true;
-               }
-               c_iter_hi->mask = D64_HI(chain[iter].mask);
-               c_iter_lo->mask = D64_LO(chain[iter].mask);
-               c_iter_hi->datum = D64_HI(chain[iter].datum);
-               c_iter_lo->datum = D64_LO(chain[iter].datum);
-
-               /* fixup the mask/datum */
-               _db_node_mask_fixup(c_iter_hi);
-               _db_node_mask_fixup(c_iter_lo);
-
-               /* link the hi and lo chain nodes */
-               c_iter_hi->nxt_t = c_iter_lo;
-
-               c_prev_hi = c_iter_hi;
-               c_prev_lo = c_iter_lo;
-       }
-       if (c_iter_lo != NULL) {
-               /* set the leaf node */
-               if (!tf_flag) {
-                       c_iter_lo->act_f_flg = true;
-                       c_iter_lo->act_f = action;
-                       c_iter_hi->act_f_flg = true;
-                       c_iter_hi->act_f = action;
-               } else {
-                       c_iter_lo->act_t_flg = true;
-                       c_iter_lo->act_t = action;
-               }
-       } else
-               s_new->action = action;
-
-       return s_new;
-
-gen_64_failure:
-       /* free the new chain and its syscall struct */
-       _db_tree_free(s_new->chains);
-       free(s_new);
-       return NULL;
-}
-
-/**
- * Generate a new filter rule for a 32 bit system
- * @param arch the architecture definition
- * @param action the filter action
- * @param syscall the syscall number
- * @param chain argument filter chain
- *
- * This function generates a new syscall filter for a 32 bit system. Returns
- * zero on success, negative values on failure.
- *
- */
-static struct db_sys_list *_db_rule_gen_32(const struct arch_def *arch,
-                                          uint32_t action,
-                                          unsigned int syscall,
-                                          struct db_api_arg *chain)
-{
-       unsigned int iter;
-       int chain_len_max;
-       struct db_sys_list *s_new;
-       struct db_arg_chain_tree *c_iter = NULL, *c_prev = NULL;
-       bool tf_flag;
-
-       s_new = malloc(sizeof(*s_new));
-       if (s_new == NULL)
-               return NULL;
-       memset(s_new, 0, sizeof(*s_new));
-       s_new->num = syscall;
-       s_new->valid = true;
-       /* run through the argument chain */
-       chain_len_max = arch_arg_count_max(arch);
-       if (chain_len_max < 0)
-               goto gen_32_failure;
-       for (iter = 0; iter < chain_len_max; iter++) {
-               if (chain[iter].valid == 0)
-                       continue;
-
-               /* skip generating instructions which are no-ops */
-               if (!_db_arg_cmp_need_lo(&chain[iter]))
-                       continue;
-
-               c_iter = malloc(sizeof(*c_iter));
-               if (c_iter == NULL)
-                       goto gen_32_failure;
-               memset(c_iter, 0, sizeof(*c_iter));
-               c_iter->refcnt = 1;
-               c_iter->arg = chain[iter].arg;
-               c_iter->arg_offset = arch_arg_offset(arch, c_iter->arg);
-               c_iter->op = chain[iter].op;
-               /* implicitly strips off the upper 32 bit */
-               c_iter->mask = chain[iter].mask;
-               c_iter->datum = chain[iter].datum;
-
-               /* link in the new node and update the chain */
-               if (c_prev != NULL) {
-                       if (tf_flag)
-                               c_prev->nxt_t = c_iter;
-                       else
-                               c_prev->nxt_f = c_iter;
-               } else
-                       s_new->chains = c_iter;
-               s_new->node_cnt++;
-
-               /* rewrite the op to reduce the op/datum combos */
-               switch (c_iter->op) {
-               case SCMP_CMP_NE:
-                       c_iter->op = SCMP_CMP_EQ;
-                       tf_flag = false;
-                       break;
-               case SCMP_CMP_LT:
-                       c_iter->op = SCMP_CMP_GE;
-                       tf_flag = false;
-                       break;
-               case SCMP_CMP_LE:
-                       c_iter->op = SCMP_CMP_GT;
-                       tf_flag = false;
-                       break;
-               default:
-                       tf_flag = true;
-               }
-
-               /* fixup the mask/datum */
-               _db_node_mask_fixup(c_iter);
-
-               c_prev = c_iter;
-       }
-       if (c_iter != NULL) {
-               /* set the leaf node */
-               if (tf_flag) {
-                       c_iter->act_t_flg = true;
-                       c_iter->act_t = action;
-               } else {
-                       c_iter->act_f_flg = true;
-                       c_iter->act_f = action;
-               }
-       } else
-               s_new->action = action;
-
-       return s_new;
-
-gen_32_failure:
-       /* free the new chain and its syscall struct */
-       _db_tree_free(s_new->chains);
-       free(s_new);
-       return NULL;
-}
-
-/**
- * Add a new rule to the seccomp filter DB
- * @param db the seccomp filter db
- * @param rule the filter rule
- *
- * This function adds a new syscall filter to the seccomp filter DB, adding to
- * the existing filters for the syscall, unless no argument specific filters
- * are present (filtering only on the syscall).  When adding new chains, the
- * shortest chain, or most inclusive filter match, will be entered into the
- * filter DB. Returns zero on success, negative values on failure.
- *
- */
-int db_rule_add(struct db_filter *db, const struct db_api_rule_list *rule)
-{
-       int rc = -ENOMEM;
-       int syscall = rule->syscall;
-       uint32_t action = rule->action;
-       struct db_api_arg *chain = rule->args;
-       struct db_sys_list *s_new, *s_iter, *s_prev = NULL;
-       struct db_arg_chain_tree *c_iter = NULL, *c_prev = NULL;
-       struct db_arg_chain_tree *ec_iter;
-       struct db_prune_state state;
-       bool rm_flag = false;
-       unsigned int new_chain_cnt = 0;
-       unsigned int n_cnt;
-
-       assert(db != NULL);
-
-       /* do all our possible memory allocation up front so we don't have to
-        * worry about failure once we get to the point where we start updating
-        * the filter db */
-       if (db->arch->size == ARCH_SIZE_64)
-               s_new = _db_rule_gen_64(db->arch, action, syscall, chain);
-       else if (db->arch->size == ARCH_SIZE_32)
-               s_new = _db_rule_gen_32(db->arch, action, syscall, chain);
-       else
-               return -EFAULT;
-       if (s_new == NULL)
-               return -ENOMEM;
-       new_chain_cnt = s_new->node_cnt;
-
-       /* no more failures allowed after this point that would result in the
-        * stored filter being in an inconsistent state */
-
-       /* find a matching syscall/chain or insert a new one */
-       s_iter = db->syscalls;
-       while (s_iter != NULL && s_iter->num < syscall) {
-               s_prev = s_iter;
-               s_iter = s_iter->next;
-       }
-add_reset:
-       s_new->node_cnt = new_chain_cnt;
-       s_new->priority = _DB_PRI_MASK_CHAIN - s_new->node_cnt;
-       c_prev = NULL;
-       c_iter = s_new->chains;
-       if (s_iter != NULL)
-               ec_iter = s_iter->chains;
-       else
-               ec_iter = NULL;
-       if (s_iter == NULL || s_iter->num != syscall) {
-               /* new syscall, add before s_iter */
-               if (s_prev != NULL) {
-                       s_new->next = s_prev->next;
-                       s_prev->next = s_new;
-               } else {
-                       s_new->next = db->syscalls;
-                       db->syscalls = s_new;
-               }
-               return 0;
-       } else if (s_iter->chains == NULL) {
-               if (rm_flag || !s_iter->valid) {
-                       /* we are here because our previous pass cleared the
-                        * entire syscall chain when searching for a subtree
-                        * match or the existing syscall entry is a phantom,
-                        * so either way add the new chain */
-                       s_iter->chains = s_new->chains;
-                       s_iter->action = s_new->action;
-                       s_iter->node_cnt = s_new->node_cnt;
-                       if (s_iter->valid)
-                               s_iter->priority = s_new->priority;
-                       s_iter->valid = true;
-                       free(s_new);
-                       rc = 0;
-                       goto add_priority_update;
-               } else
-                       /* syscall exists without any chains - existing filter
-                        * is at least as large as the new entry so cleanup and
-                        * exit */
-                       goto add_free_ok;
-       } else if (s_iter->chains != NULL && s_new->chains == NULL) {
-               /* syscall exists with chains but the new filter has no chains
-                * so we need to clear the existing chains and exit */
-               _db_tree_free(s_iter->chains);
-               s_iter->chains = NULL;
-               s_iter->node_cnt = 0;
-               s_iter->action = action;
-               goto add_free_ok;
-       }
-
-       /* check for sub-tree matches */
-       memset(&state, 0, sizeof(state));
-       rc = _db_tree_sub_prune(&(s_iter->chains), ec_iter, c_iter, &state);
-       if (rc > 0) {
-               rm_flag = true;
-               s_iter->node_cnt -= rc;
-               goto add_reset;
-       } else if (rc < 0)
-               goto add_free_ok;
-
-       /* syscall exists and has at least one existing chain - start at the
-        * top and walk the two chains */
-       do {
-               /* insert the new rule into the existing tree */
-               if (db_chain_eq(c_iter, ec_iter)) {
-                       /* found a matching node on this chain level */
-                       if (db_chain_action(c_iter) &&
-                           db_chain_action(ec_iter)) {
-                               /* both are "action" nodes */
-                               if (c_iter->act_t_flg && ec_iter->act_t_flg) {
-                                       if (ec_iter->act_t != action)
-                                               goto add_free_exist;
-                               } else if (c_iter->act_t_flg) {
-                                       ec_iter->act_t_flg = true;
-                                       ec_iter->act_t = action;
-                               }
-                               if (c_iter->act_f_flg && ec_iter->act_f_flg) {
-                                       if (ec_iter->act_f != action)
-                                               goto add_free_exist;
-                               } else if (c_iter->act_f_flg) {
-                                       ec_iter->act_f_flg = true;
-                                       ec_iter->act_f = action;
-                               }
-                               if (ec_iter->act_t_flg == ec_iter->act_f_flg &&
-                                   ec_iter->act_t == ec_iter->act_f) {
-                                       n_cnt = _db_tree_remove(
-                                                       &(s_iter->chains),
-                                                       ec_iter);
-                                       s_iter->node_cnt -= n_cnt;
-                                       goto add_free_ok;
-                               }
-                       } else if (db_chain_action(c_iter)) {
-                               /* new is shorter */
-                               if (c_iter->act_t_flg) {
-                                       rc = _db_tree_act_check(ec_iter->nxt_t,
-                                                               action);
-                                       if (rc < 0)
-                                               goto add_free;
-                                       n_cnt = _db_tree_free(ec_iter->nxt_t);
-                                       ec_iter->nxt_t = NULL;
-                                       ec_iter->act_t_flg = true;
-                                       ec_iter->act_t = action;
-                               } else {
-                                       rc = _db_tree_act_check(ec_iter->nxt_f,
-                                                               action);
-                                       if (rc < 0)
-                                               goto add_free;
-                                       n_cnt = _db_tree_free(ec_iter->nxt_f);
-                                       ec_iter->nxt_f = NULL;
-                                       ec_iter->act_f_flg = true;
-                                       ec_iter->act_f = action;
-                               }
-                               s_iter->node_cnt -= n_cnt;
-                       }
-                       if (c_iter->nxt_t != NULL) {
-                               if (ec_iter->nxt_t != NULL) {
-                                       /* jump to the next level */
-                                       c_prev = c_iter;
-                                       c_iter = c_iter->nxt_t;
-                                       ec_iter = ec_iter->nxt_t;
-                                       s_new->node_cnt--;
-                               } else if (ec_iter->act_t_flg) {
-                                       /* existing is shorter */
-                                       if (ec_iter->act_t == action)
-                                               goto add_free_ok;
-                                       goto add_free_exist;
-                               } else {
-                                       /* add a new branch */
-                                       c_prev = c_iter;
-                                       ec_iter->nxt_t = c_iter->nxt_t;
-                                       s_iter->node_cnt +=
-                                               (s_new->node_cnt - 1);
-                                       goto add_free_match;
-                               }
-                       } else if (c_iter->nxt_f != NULL) {
-                               if (ec_iter->nxt_f != NULL) {
-                                       /* jump to the next level */
-                                       c_prev = c_iter;
-                                       c_iter = c_iter->nxt_f;
-                                       ec_iter = ec_iter->nxt_f;
-                                       s_new->node_cnt--;
-                               } else if (ec_iter->act_f_flg) {
-                                       /* existing is shorter */
-                                       if (ec_iter->act_f == action)
-                                               goto add_free_ok;
-                                       goto add_free_exist;
-                               } else {
-                                       /* add a new branch */
-                                       c_prev = c_iter;
-                                       ec_iter->nxt_f = c_iter->nxt_f;
-                                       s_iter->node_cnt +=
-                                               (s_new->node_cnt - 1);
-                                       goto add_free_match;
-                               }
-                       } else
-                               goto add_free_ok;
-               } else {
-                       /* need to check other nodes on this level */
-                       if (db_chain_lt(c_iter, ec_iter)) {
-                               if (ec_iter->lvl_prv == NULL) {
-                                       /* add to the start of the level */
-                                       ec_iter->lvl_prv = c_iter;
-                                       c_iter->lvl_nxt = ec_iter;
-                                       if (ec_iter == s_iter->chains)
-                                               s_iter->chains = c_iter;
-                                       s_iter->node_cnt += s_new->node_cnt;
-                                       goto add_free_match;
-                               } else
-                                       ec_iter = ec_iter->lvl_prv;
-                       } else {
-                               if (ec_iter->lvl_nxt == NULL) {
-                                       /* add to the end of the level */
-                                       ec_iter->lvl_nxt = c_iter;
-                                       c_iter->lvl_prv = ec_iter;
-                                       s_iter->node_cnt += s_new->node_cnt;
-                                       goto add_free_match;
-                               } else if (db_chain_lt(c_iter,
-                                                      ec_iter->lvl_nxt)) {
-                                       /* add new chain in between */
-                                       c_iter->lvl_nxt = ec_iter->lvl_nxt;
-                                       ec_iter->lvl_nxt->lvl_prv = c_iter;
-                                       ec_iter->lvl_nxt = c_iter;
-                                       c_iter->lvl_prv = ec_iter;
-                                       s_iter->node_cnt += s_new->node_cnt;
-                                       goto add_free_match;
-                               } else
-                                       ec_iter = ec_iter->lvl_nxt;
-                       }
-               }
-       } while ((c_iter != NULL) && (ec_iter != NULL));
-
-       /* we should never be here! */
-       return -EFAULT;
-
-add_free_exist:
-       rc = -EEXIST;
-       goto add_free;
-add_free_ok:
-       rc = 0;
-add_free:
-       /* free the new chain and its syscall struct */
-       _db_tree_free(s_new->chains);
-       free(s_new);
-       goto add_priority_update;
-add_free_match:
-       /* free the matching portion of new chain */
-       if (c_prev != NULL) {
-               c_prev->nxt_t = NULL;
-               c_prev->nxt_f = NULL;
-               _db_tree_free(s_new->chains);
-       }
-       free(s_new);
-       rc = 0;
-add_priority_update:
-       /* update the priority */
-       if (s_iter != NULL) {
-               s_iter->priority &= (~_DB_PRI_MASK_CHAIN);
-               s_iter->priority |= (_DB_PRI_MASK_CHAIN - s_iter->node_cnt);
-       }
-       return rc;
-}
-
-/**
- * Set the priority of a given syscall
- * @param col the filter collection
- * @param syscall the syscall number
- * @param priority priority value, higher value == higher priority
- *
- * This function sets the priority of the given syscall; this value is used
- * when generating the seccomp filter code such that higher priority syscalls
- * will incur less filter code overhead than the lower priority syscalls in the
- * filter.  Returns zero on success, negative values on failure.
- *
- */
-int db_col_syscall_priority(struct db_filter_col *col,
-                           int syscall, uint8_t priority)
-{
-       int rc = 0, rc_tmp;
-       unsigned int iter;
-       int sc_tmp;
-       struct db_filter *filter;
-
-       for (iter = 0; iter < col->filter_cnt; iter++) {
-               filter = col->filters[iter];
-               sc_tmp = syscall;
-
-               rc_tmp = arch_syscall_translate(filter->arch, &sc_tmp);
-               if (rc_tmp < 0)
-                       goto priority_failure;
-
-               /* if this is a pseudo syscall (syscall < 0) then we need to
-                * rewrite the syscall for some arch specific reason */
-               if (sc_tmp < 0) {
-                       /* we set this as a strict op - we don't really care
-                        * since priorities are a "best effort" thing - as we
-                        * want to catch the -EDOM error and bail on this
-                        * architecture */
-                       rc_tmp = arch_syscall_rewrite(filter->arch, &sc_tmp);
-                       if (rc_tmp == -EDOM)
-                               continue;
-                       if (rc_tmp < 0)
-                               goto priority_failure;
-               }
-
-               rc_tmp = _db_syscall_priority(filter, sc_tmp, priority);
-
-priority_failure:
-               if (rc == 0 && rc_tmp < 0)
-                       rc = rc_tmp;
-       }
-
-       return rc;
-}
-
-/**
- * Add a new rule to the current filter
- * @param col the filter collection
- * @param strict the strict flag
- * @param action the filter action
- * @param syscall the syscall number
- * @param arg_cnt the number of argument filters in the argument filter chain
- * @param arg_array the argument filter chain, (uint, enum scmp_compare, ulong)
- *
- * 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 db_col_rule_add(struct db_filter_col *col,
-                   bool strict, uint32_t action, int syscall,
-                   unsigned int arg_cnt, const struct scmp_arg_cmp *arg_array)
-{
-       int rc = 0, rc_tmp;
-       unsigned int iter;
-       unsigned int chain_len;
-       unsigned int arg_num;
-       size_t chain_size;
-       struct db_api_arg *chain = NULL;
-       struct scmp_arg_cmp arg_data;
-
-       /* collect the arguments for the filter rule */
-       chain_len = ARG_COUNT_MAX;
-       chain_size = sizeof(*chain) * chain_len;
-       chain = malloc(chain_size);
-       if (chain == NULL)
-               return -ENOMEM;
-       memset(chain, 0, chain_size);
-       for (iter = 0; iter < arg_cnt; iter++) {
-               arg_data = arg_array[iter];
-               arg_num = arg_data.arg;
-               if (arg_num < chain_len && chain[arg_num].valid == 0) {
-                       chain[arg_num].valid = 1;
-                       chain[arg_num].arg = arg_num;
-                       chain[arg_num].op = arg_data.op;
-                       /* XXX - we should check datum/mask size against the
-                        *       arch definition, e.g. 64 bit datum on x86 */
-                       switch (chain[arg_num].op) {
-                       case SCMP_CMP_NE:
-                       case SCMP_CMP_LT:
-                       case SCMP_CMP_LE:
-                       case SCMP_CMP_EQ:
-                       case SCMP_CMP_GE:
-                       case SCMP_CMP_GT:
-                               chain[arg_num].mask = DATUM_MAX;
-                               chain[arg_num].datum = arg_data.datum_a;
-                               break;
-                       case SCMP_CMP_MASKED_EQ:
-                               chain[arg_num].mask = arg_data.datum_a;
-                               chain[arg_num].datum = arg_data.datum_b;
-                               break;
-                       default:
-                               rc = -EINVAL;
-                               goto add_return;
-                       }
-               } else {
-                       rc = -EINVAL;
-                       goto add_return;
-               }
-       }
-
-       for (iter = 0; iter < col->filter_cnt; iter++) {
-               rc_tmp = arch_filter_rule_add(col, col->filters[iter], strict,
-                                             action, syscall,
-                                             chain_len, chain);
-               if (rc == 0 && rc_tmp < 0)
-                       rc = rc_tmp;
-       }
-
-add_return:
-       if (chain != NULL)
-               free(chain);
-       return rc;
-}
-
-/**
- * Start a new seccomp filter transaction
- * @param col the filter collection
- *
- * This function starts a new seccomp filter transaction for the given filter
- * collection.  Returns zero on success, negative values on failure.
- *
- */
-int db_col_transaction_start(struct db_filter_col *col)
-{
-       unsigned int iter;
-       size_t args_size;
-       struct db_filter_snap *snap;
-       struct db_filter *filter_o, *filter_s;
-       struct db_api_rule_list *rule_o, *rule_s;
-
-       /* allocate the snapshot */
-       snap = malloc(sizeof(*snap));
-       if (snap == NULL)
-               return -ENOMEM;
-       snap->filters = malloc(sizeof(struct db_filter *) * col->filter_cnt);
-       if (snap->filters == NULL) {
-               free(snap);
-               return -ENOMEM;
-       }
-       snap->filter_cnt = col->filter_cnt;
-       for (iter = 0; iter < snap->filter_cnt; iter++)
-               snap->filters[iter] = NULL;
-       snap->next = NULL;
-
-       /* create a snapshot of the current filter state */
-       for (iter = 0; iter < col->filter_cnt; iter++) {
-               /* allocate a new filter */
-               filter_o = col->filters[iter];
-               filter_s = _db_init(filter_o->arch);
-               if (filter_s == NULL)
-                       goto trans_start_failure;
-               snap->filters[iter] = filter_s;
-
-               /* create a filter snapshot from existing rules */
-               rule_o = filter_o->rules;
-               if (rule_o == NULL)
-                       continue;
-               do {
-                       /* copy the rule */
-                       rule_s = malloc(sizeof(*rule_s));
-                       if (rule_s == NULL)
-                               goto trans_start_failure;
-                       args_size = sizeof(*rule_s->args) * rule_o->args_cnt;
-                       rule_s->args = malloc(args_size);
-                       if (rule_s->args == NULL) {
-                               free(rule_s);
-                               goto trans_start_failure;
-                       }
-                       rule_s->action = rule_o->action;
-                       rule_s->syscall = rule_o->syscall;
-                       rule_s->args_cnt = rule_o->args_cnt;
-                       memcpy(rule_s->args, rule_o->args, args_size);
-                       if (filter_s->rules != NULL) {
-                               rule_s->prev = filter_s->rules->prev;
-                               rule_s->next = filter_s->rules;
-                               filter_s->rules->prev->next = rule_s;
-                               filter_s->rules->prev = rule_s;
-                       } else {
-                               rule_s->prev = rule_s;
-                               rule_s->next = rule_s;
-                               filter_s->rules = rule_s;
-                       }
-
-                       /* insert the rule into the filter */
-                       if (db_rule_add(filter_s, rule_o) != 0)
-                               goto trans_start_failure;
-
-                       /* next rule */
-                       rule_o = rule_o->next;
-               } while (rule_o != filter_o->rules);
-       }
-
-       /* add the snapshot to the list */
-       snap->next = col->snapshots;
-       col->snapshots = snap;
-
-       return 0;
-
-trans_start_failure:
-       _db_snap_release(snap);
-       return -ENOMEM;
-}
-
-/**
- * Abort the top most seccomp filter transaction
- * @param col the filter collection
- *
- * This function aborts the most recent seccomp filter transaction.
- *
- */
-void db_col_transaction_abort(struct db_filter_col *col)
-{
-       int iter;
-       unsigned int filter_cnt;
-       struct db_filter **filters;
-       struct db_filter_snap *snap;
-
-       if (col->snapshots == NULL)
-               return;
-
-       /* replace the current filter with the last snapshot */
-       snap = col->snapshots;
-       col->snapshots = snap->next;
-       filter_cnt = col->filter_cnt;
-       filters = col->filters;
-       col->filter_cnt = snap->filter_cnt;
-       col->filters = snap->filters;
-       free(snap);
-
-       /* free the filter we swapped out */
-       for (iter = 0; iter < filter_cnt; iter++)
-               _db_release(filters[iter]);
-       free(filters);
-}
-
-/**
- * Commit the top most seccomp filter transaction
- * @param col the filter collection
- *
- * This function commits the most recent seccomp filter transaction.
- *
- */
-void db_col_transaction_commit(struct db_filter_col *col)
-{
-       struct db_filter_snap *snap;
-
-       snap = col->snapshots;
-       col->snapshots = snap->next;
-       _db_snap_release(snap);
-}
This page took 0.033846 seconds and 4 git commands to generate.