summaryrefslogtreecommitdiff
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
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>
-rw-r--r--src/db.c172
-rw-r--r--src/db.h17
2 files changed, 187 insertions, 2 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);
+}
diff --git a/src/db.h b/src/db.h
index b611a10..02e9394 100644
--- a/src/db.h
+++ b/src/db.h
@@ -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>
*/
@@ -151,6 +151,14 @@ struct db_filter {
struct db_api_rule_list *rules;
};
+struct db_filter_snap {
+ /* individual filters */
+ struct db_filter **filters;
+ unsigned int filter_cnt;
+
+ struct db_filter_snap *next;
+};
+
struct db_filter_col {
/* verification / state */
int state;
@@ -162,6 +170,9 @@ struct db_filter_col {
int endian;
struct db_filter **filters;
unsigned int filter_cnt;
+
+ /* transaction snapshots */
+ struct db_filter_snap *snapshots;
};
/**
@@ -204,4 +215,8 @@ int db_col_rule_add(struct db_filter_col *col,
int db_col_syscall_priority(struct db_filter_col *col,
int syscall, uint8_t priority);
+int db_col_transaction_start(struct db_filter_col *col);
+void db_col_transaction_abort(struct db_filter_col *col);
+void db_col_transaction_commit(struct db_filter_col *col);
+
#endif