[PATCH nft 3/4] evaluate: support for bitfield payload statement with binary operation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Update bitfield payload statement support to allow for bitwise
and/or/xor updates. Adjust payload expression to fetch 16-bits for
mangling while leaving unmodified bits intact.

 # nft --debug=netlink add rule x y ip dscp set ip dscp or 0x1
 ip x y
   [ payload load 2b @ network header + 0 => reg 1 ]
   [ bitwise reg 1 = ( reg 1 & 0x0000fbff ) ^ 0x00000400 ]
   [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]

Skip expr_evaluate_bits() transformation since these are only useful
for payload matching and set lookups.

Listing still shows a raw expression:

  # nft list ruleset
    ...
                    @nh,8,5 set 0x0

The follow up patch completes it:

  ("netlink_delinearize: support for bitfield payload statement with binary operation")

Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1698
Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
---
 src/evaluate.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 63 insertions(+), 2 deletions(-)

diff --git a/src/evaluate.c b/src/evaluate.c
index d7915ed19d59..c9c56588cee4 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -569,6 +569,13 @@ static int expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
 	uint8_t shift;
 	mpz_t bitmask;
 
+	/* payload statement with relational expression as a value does not
+	 * require the transformations that are needed for payload matching,
+	 * skip this.
+	 */
+	if (ctx->stmt && ctx->stmt->ops->type == STMT_PAYLOAD)
+		return 0;
+
 	switch (expr->etype) {
 	case EXPR_PAYLOAD:
 		shift = expr_offset_shift(expr, expr->payload.offset,
@@ -3281,10 +3288,10 @@ static int stmt_evaluate_exthdr(struct eval_ctx *ctx, struct stmt *stmt)
 
 static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
 {
-	struct expr *mask, *and, *xor, *payload_bytes;
-	unsigned int masklen, extra_len = 0;
+	struct expr *mask, *and, *xor, *expr, *payload_bytes;
 	unsigned int payload_byte_size, payload_byte_offset;
 	uint8_t shift_imm, data[NFT_REG_SIZE];
+	unsigned int masklen, extra_len = 0;
 	struct expr *payload;
 	mpz_t bitmask, ff;
 	bool need_csum;
@@ -3350,6 +3357,60 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
 		if (shift_imm)
 			mpz_lshift_ui(stmt->payload.val->value, shift_imm);
 		break;
+	case EXPR_BINOP:
+		expr = stmt->payload.val;
+		while (expr->left->etype == EXPR_BINOP)
+			expr = expr->left;
+
+		if (expr->left->etype != EXPR_PAYLOAD)
+			break;
+
+		if (!payload_expr_cmp(payload, expr->left))
+			break;
+
+		/* Adjust payload to fetch 16-bits. */
+		expr->left->payload.offset = payload_byte_offset * BITS_PER_BYTE;
+		expr->left->len = payload_byte_size * BITS_PER_BYTE;
+		expr->left->payload.is_raw = 1;
+
+		switch (expr->right->etype) {
+		case EXPR_VALUE:
+			if (shift_imm)
+				mpz_lshift_ui(expr->right->value, shift_imm);
+
+			/* build bitmask to keep unmodified bits intact */
+			if (expr->op == OP_AND) {
+				masklen = payload_byte_size * BITS_PER_BYTE;
+				mpz_init_bitmask(ff, masklen);
+
+				mpz_init2(bitmask, masklen);
+				mpz_bitmask(bitmask, payload->len);
+				mpz_lshift_ui(bitmask, shift_imm);
+
+				mpz_xor(bitmask, ff, bitmask);
+				mpz_clear(ff);
+
+				mpz_ior(bitmask, expr->right->value, bitmask);
+				mpz_set(expr->right->value, bitmask);
+
+				mpz_clear(bitmask);
+			}
+			break;
+		default:
+			return expr_error(ctx->msgs, expr->right,
+					  "payload statement for this expression is not supported");
+		}
+
+		expr_free(stmt->payload.expr);
+		/* statement payload is the same in expr and value, update it. */
+		stmt->payload.expr = expr_clone(expr->left);
+		payload = stmt->payload.expr;
+		ctx->stmt_len = stmt->payload.expr->len;
+
+		if (expr_evaluate(ctx, &stmt->payload.val) < 0)
+			return -1;
+
+		return 0;
 	default:
 		return expr_error(ctx->msgs, stmt->payload.val,
 				  "payload statement for this expression is not supported");
-- 
2.30.2





[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux