[CRIU] [PATCH 20/27] seccomp: Try use tsync flag if possible

Cyrill Gorcunov gorcunov at openvz.org
Thu Mar 1 15:41:42 MSK 2018


Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 criu/seccomp.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/criu/seccomp.c b/criu/seccomp.c
index dd608265731a..63f1e98296cb 100644
--- a/criu/seccomp.c
+++ b/criu/seccomp.c
@@ -192,6 +192,78 @@ static int collect_filter(struct seccomp_entry *entry)
 	return 0;
 }
 
+/*
+ * When filter is being set up with SECCOMP_FILTER_FLAG_TSYNC then all
+ * threads share same filters chain. Still without kernel support we
+ * don't know if the chains are indeed were propagated by the flag above
+ * or application installed identical chains manually.
+ *
+ * Thus we do a trick: if all threads are sharing chains we just drop
+ * all ones except on a leader and assign SECCOMP_FILTER_FLAG_TSYNC there.
+ * The rationale is simple: if application is using tsync it always can
+ * assign new not-tsync filters after, but in reverse if we don't provide
+ * tsync on restore the further calls with tsync will fail later.
+ *
+ * Proper fix needs some support from kernel side (presumably kcmp mode).
+ */
+static void try_use_tsync(struct seccomp_entry *leader, struct pstree_item *item)
+{
+	struct seccomp_filter_chain *chain_a, *chain_b;
+	struct seccomp_entry *entry;
+	size_t i, j;
+
+	if (leader->mode != SECCOMP_MODE_FILTER)
+		return;
+
+	for (i = 0; i < item->nr_threads; i++) {
+		entry = seccomp_find_entry(item->threads[i]->real);
+		BUG_ON(!entry);
+
+		if (entry == leader)
+			continue;
+
+		if (entry->mode != leader->mode ||
+		    entry->nr_chains != leader->nr_chains)
+			return;
+
+		chain_a = leader->chain;
+		chain_b = entry->chain;
+
+		for (j = 0; j < leader->nr_chains; j++) {
+			BUG_ON((!chain_a || !chain_b));
+
+			if (chain_a->filter.filter.len !=
+			    chain_b->filter.filter.len)
+				return;
+
+			if (memcmp(chain_a->filter.filter.data,
+				   chain_b->filter.filter.data,
+				   chain_a->filter.filter.len))
+				return;
+
+			chain_a = chain_a->prev;
+			chain_b = chain_b->prev;
+		}
+	}
+
+	/* OK, so threads can be restored with tsync */
+	pr_debug("Use SECCOMP_FILTER_FLAG_TSYNC for tid_real %d\n",
+		 leader->tid_real);
+
+	for (chain_a = leader->chain; chain_a; chain_a = chain_a->prev)
+		chain_a->filter.flags |= SECCOMP_FILTER_FLAG_TSYNC;
+
+	for (i = 0; i < item->nr_threads; i++) {
+		entry = seccomp_find_entry(item->threads[i]->real);
+		BUG_ON(!entry);
+
+		if (entry == leader)
+			continue;
+
+		seccomp_free_chain(entry);
+	}
+}
+
 static int collect_filters(struct pstree_item *item)
 {
 	struct seccomp_entry *parent, *leader, *entry;
@@ -225,6 +297,7 @@ static int collect_filters(struct pstree_item *item)
 			return -1;
 	}
 
+	try_use_tsync(leader, item);
 	return 0;
 }
 
-- 
2.14.3



More information about the CRIU mailing list