Blame SOURCES/0001-src-fix-protocol-context-update-on-big-endian-system.patch

f534eb
From ae89c5b2865f77ac5e3f8e6c74c9b07296a1acdf Mon Sep 17 00:00:00 2001
f534eb
From: Phil Sutter <psutter@redhat.com>
f534eb
Date: Thu, 14 Dec 2017 14:17:27 +0100
f534eb
Subject: [PATCH] src: fix protocol context update on big-endian systems
f534eb
f534eb
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1523016
f534eb
Upstream Status: nftables commit a2c55e04d5a11
f534eb
f534eb
commit a2c55e04d5a1187914cba2c02810db94de499ace
f534eb
Author: Phil Sutter <phil@nwl.cc>
f534eb
Date:   Sat Dec 9 16:52:29 2017 +0100
f534eb
f534eb
    src: fix protocol context update on big-endian systems
f534eb
f534eb
    There is an obscure bug on big-endian systems when trying to list a rule
f534eb
    containing the expression 'ct helper tftp' which triggers the assert()
f534eb
    call in mpz_get_type().
f534eb
f534eb
    Florian identified the cause: ct_expr_pctx_update() is called for the
f534eb
    relational expression which calls mpz_get_uint32() to get RHS value
f534eb
    (assuming it is a protocol number). On big-endian systems, the
f534eb
    misinterpreted value exceeds UINT_MAX.
f534eb
f534eb
    Expressions' pctx_update() callback should only be called for protocol
f534eb
    matches, so ct_meta_common_postprocess() lacked a check for 'left->flags
f534eb
    & EXPR_F_PROTOCOL' like the one already present in
f534eb
    payload_expr_pctx_update().
f534eb
f534eb
    In order to fix this in a clean way, this patch introduces a wrapper
f534eb
    relational_expr_pctx_update() to be used instead of directly calling
f534eb
    LHS's pctx_update() callback which unifies the necessary checks (and
f534eb
    adds one more assert):
f534eb
f534eb
    - assert(expr->ops->type == EXPR_RELATIONAL)
f534eb
      -> This is new, just to ensure the wrapper is called properly.
f534eb
    - assert(expr->op == OP_EQ)
f534eb
      -> This was moved from {ct,meta,payload}_expr_pctx_update().
f534eb
    - left->ops->pctx_update != NULL
f534eb
      -> This was taken from expr_evaluate_relational(), a necessary
f534eb
         requirement for the introduced wrapper to function at all.
f534eb
    - (left->flags & EXPR_F_PROTOCOL) != 0
f534eb
      -> The crucial missing check which led to the problem.
f534eb
f534eb
    Suggested-by: Florian Westphal <fw@strlen.de>
f534eb
    Signed-off-by: Phil Sutter <phil@nwl.cc>
f534eb
    Signed-off-by: Florian Westphal <fw@strlen.de>
f534eb
---
f534eb
 include/expression.h      |  3 +++
f534eb
 src/ct.c                  |  2 --
f534eb
 src/evaluate.c            |  6 ++----
f534eb
 src/expression.c          | 13 +++++++++++++
f534eb
 src/meta.c                |  2 --
f534eb
 src/netlink.c             |  2 +-
f534eb
 src/netlink_delinearize.c |  4 ++--
f534eb
 src/payload.c             |  7 +------
f534eb
 8 files changed, 22 insertions(+), 17 deletions(-)
f534eb
f534eb
diff --git a/include/expression.h b/include/expression.h
f534eb
index 215cbc9..915ce0b 100644
f534eb
--- a/include/expression.h
f534eb
+++ b/include/expression.h
f534eb
@@ -369,6 +369,9 @@ extern struct expr *binop_expr_alloc(const struct location *loc, enum ops op,
f534eb
 extern struct expr *relational_expr_alloc(const struct location *loc, enum ops op,
f534eb
 					  struct expr *left, struct expr *right);
f534eb
 
f534eb
+extern void relational_expr_pctx_update(struct proto_ctx *ctx,
f534eb
+					const struct expr *expr);
f534eb
+
f534eb
 extern struct expr *verdict_expr_alloc(const struct location *loc,
f534eb
 				       int verdict, const char *chain);
f534eb
 
f534eb
diff --git a/src/ct.c b/src/ct.c
f534eb
index 58b873e..8ab32e9 100644
f534eb
--- a/src/ct.c
f534eb
+++ b/src/ct.c
f534eb
@@ -327,8 +327,6 @@ static void ct_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr)
f534eb
 	const struct proto_desc *base = NULL, *desc;
f534eb
 	uint32_t nhproto;
f534eb
 
f534eb
-	assert(expr->op == OP_EQ);
f534eb
-
f534eb
 	nhproto = mpz_get_uint32(right->value);
f534eb
 
f534eb
 	base = ctx->protocol[left->ct.base].desc;
f534eb
diff --git a/src/evaluate.c b/src/evaluate.c
f534eb
index 618e188..f16bb33 100644
f534eb
--- a/src/evaluate.c
f534eb
+++ b/src/evaluate.c
f534eb
@@ -743,7 +743,7 @@ static int ct_gen_nh_dependency(struct eval_ctx *ctx, struct expr *ct)
f534eb
 				    constant_data_ptr(ct->ct.nfproto, left->len));
f534eb
 	dep = relational_expr_alloc(&ct->location, OP_EQ, left, right);
f534eb
 
f534eb
-	left->ops->pctx_update(&ctx->pctx, dep);
f534eb
+	relational_expr_pctx_update(&ctx->pctx, dep);
f534eb
 
f534eb
 	nstmt = expr_stmt_alloc(&dep->location, dep);
f534eb
 
f534eb
@@ -1632,9 +1632,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
f534eb
 		 * Update protocol context for payload and meta iiftype
f534eb
 		 * equality expressions.
f534eb
 		 */
f534eb
-		if (left->flags & EXPR_F_PROTOCOL &&
f534eb
-		    left->ops->pctx_update)
f534eb
-			left->ops->pctx_update(&ctx->pctx, rel);
f534eb
+		relational_expr_pctx_update(&ctx->pctx, rel);
f534eb
 
f534eb
 		if (left->ops->type == EXPR_CONCAT)
f534eb
 			return 0;
f534eb
diff --git a/src/expression.c b/src/expression.c
f534eb
index fc1097a..f8b560c 100644
f534eb
--- a/src/expression.c
f534eb
+++ b/src/expression.c
f534eb
@@ -600,6 +600,19 @@ struct expr *relational_expr_alloc(const struct location *loc, enum ops op,
f534eb
 	return expr;
f534eb
 }
f534eb
 
f534eb
+void relational_expr_pctx_update(struct proto_ctx *ctx,
f534eb
+				 const struct expr *expr)
f534eb
+{
f534eb
+	const struct expr *left = expr->left;
f534eb
+
f534eb
+	assert(expr->ops->type == EXPR_RELATIONAL);
f534eb
+	assert(expr->op == OP_EQ);
f534eb
+
f534eb
+	if (left->ops->pctx_update &&
f534eb
+	    (left->flags & EXPR_F_PROTOCOL))
f534eb
+		left->ops->pctx_update(ctx, expr);
f534eb
+}
f534eb
+
f534eb
 static void range_expr_print(const struct expr *expr, struct output_ctx *octx)
f534eb
 {
f534eb
 	octx->numeric += NUMERIC_ALL + 1;
f534eb
diff --git a/src/meta.c b/src/meta.c
f534eb
index 56b9e29..3c31174 100644
f534eb
--- a/src/meta.c
f534eb
+++ b/src/meta.c
f534eb
@@ -482,8 +482,6 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
f534eb
 	const struct proto_desc *desc;
f534eb
 	uint8_t protonum;
f534eb
 
f534eb
-	assert(expr->op == OP_EQ);
f534eb
-
f534eb
 	switch (left->meta.key) {
f534eb
 	case NFT_META_IIFTYPE:
f534eb
 		if (h->base < PROTO_BASE_NETWORK_HDR &&
f534eb
diff --git a/src/netlink.c b/src/netlink.c
f534eb
index d5d410a..5d6f5ce 100644
f534eb
--- a/src/netlink.c
f534eb
+++ b/src/netlink.c
f534eb
@@ -2729,7 +2729,7 @@ restart:
f534eb
 		list_add_tail(&stmt->list, &unordered);
f534eb
 
f534eb
 		desc = ctx->protocol[base].desc;
f534eb
-		lhs->ops->pctx_update(ctx, rel);
f534eb
+		relational_expr_pctx_update(ctx, rel);
f534eb
 	}
f534eb
 
f534eb
 	expr_free(rhs);
f534eb
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
f534eb
index 4432887..11fd330 100644
f534eb
--- a/src/netlink_delinearize.c
f534eb
+++ b/src/netlink_delinearize.c
f534eb
@@ -1329,7 +1329,7 @@ static void payload_match_expand(struct rule_pp_ctx *ctx,
f534eb
 		nexpr = relational_expr_alloc(&expr->location, expr->op,
f534eb
 					      left, tmp);
f534eb
 		if (expr->op == OP_EQ)
f534eb
-			left->ops->pctx_update(&ctx->pctx, nexpr);
f534eb
+			relational_expr_pctx_update(&ctx->pctx, nexpr);
f534eb
 
f534eb
 		nstmt = expr_stmt_alloc(&ctx->stmt->location, nexpr);
f534eb
 		list_add_tail(&nstmt->list, &ctx->stmt->list);
f534eb
@@ -1397,7 +1397,7 @@ static void ct_meta_common_postprocess(struct rule_pp_ctx *ctx,
f534eb
 		if (expr->right->ops->type == EXPR_RANGE)
f534eb
 			break;
f534eb
 
f534eb
-		expr->left->ops->pctx_update(&ctx->pctx, expr);
f534eb
+		relational_expr_pctx_update(&ctx->pctx, expr);
f534eb
 
f534eb
 		if (ctx->pdctx.pbase == PROTO_BASE_INVALID &&
f534eb
 		    left->flags & EXPR_F_PROTOCOL) {
f534eb
diff --git a/src/payload.c b/src/payload.c
f534eb
index aa8a95a..60090ac 100644
f534eb
--- a/src/payload.c
f534eb
+++ b/src/payload.c
f534eb
@@ -84,11 +84,6 @@ static void payload_expr_pctx_update(struct proto_ctx *ctx,
f534eb
 	const struct proto_desc *base, *desc;
f534eb
 	unsigned int proto = 0;
f534eb
 
f534eb
-	if (!(left->flags & EXPR_F_PROTOCOL))
f534eb
-		return;
f534eb
-
f534eb
-	assert(expr->op == OP_EQ);
f534eb
-
f534eb
 	/* Export the data in the correct byte order */
f534eb
 	assert(right->len / BITS_PER_BYTE <= sizeof(proto));
f534eb
 	mpz_export_data(constant_data_ptr(proto, right->len), right->value,
f534eb
@@ -240,7 +235,7 @@ static int payload_add_dependency(struct eval_ctx *ctx,
f534eb
 		return expr_error(ctx->msgs, expr,
f534eb
 					  "dependency statement is invalid");
f534eb
 	}
f534eb
-	left->ops->pctx_update(&ctx->pctx, dep);
f534eb
+	relational_expr_pctx_update(&ctx->pctx, dep);
f534eb
 	*res = stmt;
f534eb
 	return 0;
f534eb
 }
f534eb
-- 
f534eb
1.8.3.1
f534eb