summaryrefslogtreecommitdiff
path: root/src/db.c
diff options
context:
space:
mode:
authorPaul Moore <pmoore@redhat.com>2015-11-12 18:25:59 -0500
committerPaul Moore <paul@paul-moore.com>2016-02-09 08:32:15 -0500
commit9be1538a4ac0e45047a3f1b79691505c3d11ca31 (patch)
treed9ea24338bf3f9d99d64c3f286b189adb3eb6783 /src/db.c
parentf16f405f61ecdbad202257b61004b85fce64d75c (diff)
downloadlibseccomp-9be1538a4ac0e45047a3f1b79691505c3d11ca31.tar.gz
db: introduce transaction support
This patch adds basic transaction support to the db layer. The db transactions allow callers to checkpoint a filter collection at the current point in time and later rollback the filter collection if necessary. There will be some overhead at the start of the transaction to generate the checkpoint, but transaction commit and abort rollbacks are guaranteed to succeed. Transactions may be nested. Signed-off-by: Paul Moore <pmoore@redhat.com>
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);
+}