summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2025-02-27 18:36:16 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2025-03-07 13:56:47 +0100
commitee32bc90b80f329822b1dd3ee35f2eb98ae7f260 (patch)
tree026e60bac7b91350d9705d5ea0072d8349de39a3
parentde447e248cce3ca3fd7040c386ac798c35721415 (diff)
evaluate: support for bitfield payload statement with binary operation
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@netfilter.org>
-rw-r--r--src/evaluate.c65
1 files changed, 63 insertions, 2 deletions
diff --git a/src/evaluate.c b/src/evaluate.c
index d7915ed1..c9c56588 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");