From c556e8d4bebcde1ce34168fbac2d22328e19e36a Mon Sep 17 00:00:00 2001
From: LiFeng <lifeng68@huawei.com>
Date: Fri, 18 Jan 2019 02:11:11 -0500
Subject: [PATCH 050/131] seccomp: add rules for specified architecture only

LXC MR: https://github.com/lxc/lxc/pull/2786

Signed-off-by: LiFeng <lifeng68@huawei.com>
---
 src/lxc/seccomp.c | 234 ++++++++++++++++++++++++++--------------------
 1 file changed, 132 insertions(+), 102 deletions(-)

diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c
index 27bdc223..4a9143bb 100644
--- a/src/lxc/seccomp.c
+++ b/src/lxc/seccomp.c
@@ -291,7 +291,7 @@ on_error:
 #endif
 
 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
-enum lxc_hostarch_t {
+enum lxc_arch_t {
 	lxc_seccomp_arch_all = 0,
 	lxc_seccomp_arch_native,
 	lxc_seccomp_arch_i386,
@@ -345,8 +345,8 @@ int get_hostarch(void)
 	return lxc_seccomp_arch_unknown;
 }
 
-scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch,
-			    uint32_t default_policy_action, bool *needs_merge)
+scmp_filter_ctx get_new_ctx(enum lxc_arch_t n_arch,
+			    uint32_t default_policy_action)
 {
 	int ret;
 	uint32_t arch;
@@ -464,10 +464,7 @@ scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch,
 			return NULL;
 		}
 		TRACE("Removed native arch from main seccomp context");
-
-		*needs_merge = true;
 	} else {
-		*needs_merge = false;
 		TRACE("Arch %d already present in main seccomp context", (int)n_arch);
 	}
 
@@ -550,6 +547,27 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
 	return true;
 }
 
+#define SCMP_ARCH_INDEX_MAX 3
+
+struct scmp_ctx_info {
+	uint32_t architectures[SCMP_ARCH_INDEX_MAX];
+	enum lxc_arch_t lxc_arch[SCMP_ARCH_INDEX_MAX];
+	scmp_filter_ctx contexts[SCMP_ARCH_INDEX_MAX];
+	bool needs_merge[SCMP_ARCH_INDEX_MAX];
+};
+
+static int get_arch_index(enum lxc_arch_t arch, struct scmp_ctx_info *ctx)
+{
+	int i;
+
+	for (i = 0; i < SCMP_ARCH_INDEX_MAX; i++) {
+		if (ctx->lxc_arch[i] == arch)
+			return i;
+	}
+
+	return -1;
+}
+
 /*
  * v2 consists of
  * [x86]
@@ -568,15 +586,11 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c
 {
 	int ret;
 	char *p;
-	enum lxc_hostarch_t cur_rule_arch, native_arch;
+	enum lxc_arch_t cur_rule_arch, native_arch;
 	bool blacklist = false;
 	uint32_t default_policy_action = -1, default_rule_action = -1;
 	struct seccomp_v2_rule rule;
-	struct scmp_ctx_info {
-		uint32_t architectures[3];
-		scmp_filter_ctx contexts[3];
-		bool needs_merge[3];
-	} ctx;
+	struct scmp_ctx_info ctx;
 
 	if (strncmp(line, "blacklist", 9) == 0)
 		blacklist = true;
@@ -617,23 +631,23 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c
 		cur_rule_arch = lxc_seccomp_arch_all;
 
 		ctx.architectures[0] = SCMP_ARCH_X86;
+		ctx.lxc_arch[0] = lxc_seccomp_arch_i386;
 		ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_i386,
-					      default_policy_action,
-					      &ctx.needs_merge[0]);
+					      default_policy_action);
 		if (!ctx.contexts[0])
 			goto bad;
 
 		ctx.architectures[1] = SCMP_ARCH_X32;
+		ctx.lxc_arch[1] = lxc_seccomp_arch_x32;
 		ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_x32,
-					      default_policy_action,
-					      &ctx.needs_merge[1]);
+					      default_policy_action);
 		if (!ctx.contexts[1])
 			goto bad;
 
 		ctx.architectures[2] = SCMP_ARCH_X86_64;
+		ctx.lxc_arch[2] = lxc_seccomp_arch_amd64;
 		ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_amd64,
-					      default_policy_action,
-					      &ctx.needs_merge[2]);
+					      default_policy_action);
 		if (!ctx.contexts[2])
 			goto bad;
 #ifdef SCMP_ARCH_PPC
@@ -641,17 +655,17 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c
 		cur_rule_arch = lxc_seccomp_arch_all;
 
 		ctx.architectures[0] = SCMP_ARCH_PPC;
+		ctx.lxc_arch[0] = lxc_seccomp_arch_ppc;
 		ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_ppc,
-					      default_policy_action,
-					      &ctx.needs_merge[0]);
+					      default_policy_action);
 		if (!ctx.contexts[0])
 			goto bad;
 
-		ctx.architectures[2] = SCMP_ARCH_PPC64;
-		ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_ppc64,
-					      default_policy_action,
-					      &ctx.needs_merge[2]);
-		if (!ctx.contexts[2])
+		ctx.architectures[1] = SCMP_ARCH_PPC64;
+		ctx.lxc_arch[1] = lxc_seccomp_arch_ppc64;
+		ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_ppc64,
+					      default_policy_action);
+		if (!ctx.contexts[1])
 			goto bad;
 #endif
 #ifdef SCMP_ARCH_ARM
@@ -659,18 +673,18 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c
 		cur_rule_arch = lxc_seccomp_arch_all;
 
 		ctx.architectures[0] = SCMP_ARCH_ARM;
+		ctx.lxc_arch[0] = lxc_seccomp_arch_arm;
 		ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_arm,
-					      default_policy_action,
-					      &ctx.needs_merge[0]);
+					      default_policy_action);
 		if (!ctx.contexts[0])
 			goto bad;
 
 #ifdef SCMP_ARCH_AARCH64
-		ctx.architectures[2] = SCMP_ARCH_AARCH64;
-		ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_arm64,
-					      default_policy_action,
-					      &ctx.needs_merge[2]);
-		if (!ctx.contexts[2])
+		ctx.architectures[1] = SCMP_ARCH_AARCH64;
+		ctx.lxc_arch[1] = lxc_seccomp_arch_arm64;
+		ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_arm64,
+					      default_policy_action);
+		if (!ctx.contexts[1])
 			goto bad;
 #endif
 #endif
@@ -679,46 +693,46 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c
 		cur_rule_arch = lxc_seccomp_arch_all;
 
 		ctx.architectures[0] = SCMP_ARCH_MIPS;
+		ctx.lxc_arch[0] = lxc_seccomp_arch_mips;
 		ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mips,
-					      default_policy_action,
-					      &ctx.needs_merge[0]);
+					      default_policy_action);
 		if (!ctx.contexts[0])
 			goto bad;
 
 		ctx.architectures[1] = SCMP_ARCH_MIPS64N32;
+		ctx.lxc_arch[1] = lxc_seccomp_arch_mips64n32;
 		ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mips64n32,
-					      default_policy_action,
-					      &ctx.needs_merge[1]);
+					      default_policy_action);
 		if (!ctx.contexts[1])
 			goto bad;
 
 		ctx.architectures[2] = SCMP_ARCH_MIPS64;
+		ctx.lxc_arch[2] = lxc_seccomp_arch_mips64;
 		ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mips64,
-					      default_policy_action,
-					      &ctx.needs_merge[2]);
+					      default_policy_action);
 		if (!ctx.contexts[2])
 			goto bad;
 	} else if (native_arch == lxc_seccomp_arch_mipsel64) {
 		cur_rule_arch = lxc_seccomp_arch_all;
 
 		ctx.architectures[0] = SCMP_ARCH_MIPSEL;
+		ctx.lxc_arch[0] = lxc_seccomp_arch_mipsel;
 		ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mipsel,
-					      default_policy_action,
-					      &ctx.needs_merge[0]);
+					      default_policy_action);
 		if (!ctx.contexts[0])
 			goto bad;
 
 		ctx.architectures[1] = SCMP_ARCH_MIPSEL64N32;
+		ctx.lxc_arch[1] = lxc_seccomp_arch_mipsel64n32;
 		ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32,
-					      default_policy_action,
-					      &ctx.needs_merge[1]);
+					      default_policy_action);
 		if (!ctx.contexts[1])
 			goto bad;
 
 		ctx.architectures[2] = SCMP_ARCH_MIPSEL64;
+		ctx.lxc_arch[2] = lxc_seccomp_arch_mipsel64;
 		ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mipsel64,
-					      default_policy_action,
-					      &ctx.needs_merge[2]);
+					      default_policy_action);
 		if (!ctx.contexts[2])
 			goto bad;
 #endif
@@ -928,97 +942,113 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c
 			goto bad_rule;
 		}
 
-		if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line,
-					 conf->seccomp_ctx, &rule))
-			goto bad_rule;
+		if (cur_rule_arch == native_arch) {
+			if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line,
+						 conf->seccomp_ctx, &rule))
+				goto bad_rule;
+
+			INFO("Added native rule for arch %d for %s action %d(%s)",
+			     SCMP_ARCH_NATIVE, line, rule.action,
+			     get_action_name(rule.action));
+		} else if (cur_rule_arch != lxc_seccomp_arch_all) {
+			int arch_index = get_arch_index(cur_rule_arch, &ctx);
+			if (arch_index < 0)
+				goto bad_arch;
 
-		INFO("Added native rule for arch %d for %s action %d(%s)",
-		     SCMP_ARCH_NATIVE, line, rule.action,
-		     get_action_name(rule.action));
+			if (!do_resolve_add_rule(ctx.architectures[arch_index], line,
+						 ctx.contexts[arch_index], &rule))
+				goto bad_rule;
 
-		if (cur_rule_arch == lxc_seccomp_arch_all) {
+			INFO("Added compat rule for arch %d for %s action %d(%s)",
+			     ctx.architectures[arch_index], line, rule.action,
+			     get_action_name(rule.action));
+			ctx.needs_merge[arch_index] = true;
+		} else {
 			if (ctx.architectures[0] != SCMP_ARCH_NATIVE) {
 				if (!do_resolve_add_rule(ctx.architectures[0], line,
-							ctx.contexts[0], &rule))
+							 ctx.contexts[0], &rule))
 					goto bad_rule;
 
-					INFO("Added compat rule for arch %d for %s action %d(%s)",
-						ctx.architectures[0], line, rule.action,
-						get_action_name(rule.action));
+				INFO("Added compat rule for arch %d for %s action %d(%s)",
+				     ctx.architectures[0], line, rule.action,
+				     get_action_name(rule.action));
+				ctx.needs_merge[0] = true;
 			}
 
 			if (ctx.architectures[1] != SCMP_ARCH_NATIVE) {
 				if (!do_resolve_add_rule(ctx.architectures[1], line,
-							ctx.contexts[1], &rule))
+							 ctx.contexts[1], &rule))
 					goto bad_rule;
 
 				INFO("Added compat rule for arch %d for %s action %d(%s)",
-					ctx.architectures[1], line, rule.action,
-					get_action_name(rule.action));
+				     ctx.architectures[1], line, rule.action,
+				     get_action_name(rule.action));
+				ctx.needs_merge[1] = true;
 			}
 
 			if (ctx.architectures[2] != SCMP_ARCH_NATIVE) {
 				if (!do_resolve_add_rule(ctx.architectures[2], line,
-						ctx.contexts[2], &rule))
+							ctx.contexts[2], &rule))
 					goto bad_rule;
 
 				INFO("Added native rule for arch %d for %s action %d(%s)",
-					ctx.architectures[2], line, rule.action,
-					get_action_name(rule.action));
+				     ctx.architectures[2], line, rule.action,
+				     get_action_name(rule.action));
+				ctx.needs_merge[2] = true;
 			}
 		}
-	}
 
-	if (cur_rule_arch == lxc_seccomp_arch_all) {
-		INFO("Merging compat seccomp contexts into main context");
-		if (ctx.contexts[0]) {
-			if (ctx.needs_merge[0]) {
-				ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[0]);
-				if (ret < 0) {
-					ERROR("Failed to merge first compat seccomp "
-				      "context into main context");
-					goto bad;
-				}
+	}
 
-				TRACE("Merged first compat seccomp context into main context");
-			} else {
-				seccomp_release(ctx.contexts[0]);
-				ctx.contexts[0] = NULL;
+	INFO("Merging compat seccomp contexts into main context");
+	if (ctx.contexts[0]) {
+		if (ctx.needs_merge[0]) {
+			ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[0]);
+			if (ret < 0) {
+				ERROR("%s - Failed to merge first compat seccomp "
+				      "context into main context", strerror(-ret));
+				goto bad;
 			}
-		}
 
-		if (ctx.contexts[1]) {
-			if (ctx.needs_merge[1]) {
-				ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[1]);
-				if (ret < 0) {
-					ERROR("Failed to merge first compat seccomp "
-					      "context into main context");
-					goto bad;
-				}
+			TRACE("Merged first compat seccomp context into main context");
+		} else {
+			seccomp_release(ctx.contexts[0]);
+			ctx.contexts[0] = NULL;
+		}
+	}
 
-				TRACE("Merged second compat seccomp context into main context");
-			} else {
-				seccomp_release(ctx.contexts[1]);
-				ctx.contexts[1] = NULL;
+	if (ctx.contexts[1]) {
+		if (ctx.needs_merge[1]) {
+			ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[1]);
+			if (ret < 0) {
+				ERROR("%s - Failed to merge second compat seccomp "
+				      "context into main context", strerror(-ret));
+				goto bad;
 			}
-		}
 
-		if (ctx.contexts[2]) {
-			if (ctx.needs_merge[2]) {
-				ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[2]);
-				if (ret < 0) {
-					ERROR("Failed to merge third compat seccomp "
-					      "context into main context");
-					goto bad;
-				}
+			TRACE("Merged second compat seccomp context into main context");
+		} else {
+			seccomp_release(ctx.contexts[1]);
+			ctx.contexts[1] = NULL;
+		}
+	}
 
-				TRACE("Merged third compat seccomp context into main context");
-			} else {
-				seccomp_release(ctx.contexts[2]);
-				ctx.contexts[2] = NULL;
+	if (ctx.contexts[2]) {
+		if (ctx.needs_merge[2]) {
+			ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[2]);
+			if (ret < 0) {
+				ERROR("%s - Failed to merge third compat seccomp "
+				      "context into main context", strerror(-ret));
+				goto bad;
 			}
+
+			TRACE("Merged third compat seccomp context into main context");
+		} else {
+			seccomp_release(ctx.contexts[2]);
+			ctx.contexts[2] = NULL;
 		}
 	}
+
 	free(line);
 	return 0;
 
-- 
2.23.0

