summaryrefslogtreecommitdiff
path: root/src/db.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/db.c')
-rw-r--r--src/db.c172
1 files changed, 171 insertions, 1 deletions
diff --git a/src/db.c b/src/db.c
index dc9ca71..321a064 100644
--- a/src/db.c
+++ b/src/db.c
@@ -1,7 +1,7 @@
/**
* Enhanced Seccomp Filter DB
*
- * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Copyright (c) 2012,2016 Red Hat <pmoore@redhat.com>
* Author: Paul Moore <pmoore@redhat.com>
*/
@@ -434,6 +434,28 @@ static void _db_release(struct db_filter *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
@@ -505,6 +527,7 @@ 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;
@@ -538,6 +561,16 @@ int db_col_reset(struct db_filter_col *col, uint32_t def_action)
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;
}
@@ -1651,3 +1684,140 @@ add_return:
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);
+}