]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
evaluate: place byteorder conversion before rshift in payload statement
authorPablo Neira Ayuso <pablo@netfilter.org>
Fri, 7 Jul 2023 21:40:19 +0000 (23:40 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 7 Jul 2023 22:33:43 +0000 (00:33 +0200)
For bitfield that spans more than one byte, such as ip6 dscp, byteorder
conversion needs to be done before rshift. Add unary expression for this
conversion only in the case of meta and ct statements.

Before this patch:

 # nft --debug=netlink add rule ip6 x y 'meta mark set ip6 dscp'
 ip6 x y
  [ payload load 2b @ network header + 0 => reg 1 ]
  [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
  [ byteorder reg 1 = ntoh(reg 1, 2, 2) ] <--------- incorrect
  [ meta set mark with reg 1 ]

After this patch:

 # nft --debug=netlink add rule ip6 x y 'meta mark set ip6 dscp'
 ip6 x y
  [ payload load 2b @ network header + 0 => reg 1 ]
  [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
  [ byteorder reg 1 = ntoh(reg 1, 2, 2) ] <-------- correct
  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
  [ meta set mark with reg 1 ]

For the matching case, binary transfer already deals with the rshift to
adjust left and right hand side of the expression, the unary conversion
is not needed in such case.

Fixes: 8221d86e616b ("tests: py: add test-cases for ct and packet mark payload expressions")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/evaluate.c
tests/py/ip6/ct.t.payload
tests/py/ip6/meta.t.payload

index 687f9a7b59240b3c9038b8da8bd6d13cec254c47..678ad9b8907d32abf2d0452f71e3d1b280fcedf9 100644 (file)
@@ -508,6 +508,7 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
 {
        struct expr *expr = *exprp, *and, *mask, *rshift, *off;
        unsigned masklen, len = expr->len, extra_len = 0;
+       enum byteorder byteorder;
        uint8_t shift;
        mpz_t bitmask;
 
@@ -542,6 +543,15 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
        and->len        = masklen;
 
        if (shift) {
+               if (ctx->stmt_len > 0 && div_round_up(masklen, BITS_PER_BYTE) > 1) {
+                       int op = byteorder_conversion_op(expr, BYTEORDER_HOST_ENDIAN);
+                       and = unary_expr_alloc(&expr->location, op, and);
+                       and->len = masklen;
+                       byteorder = BYTEORDER_HOST_ENDIAN;
+               } else {
+                       byteorder = expr->byteorder;
+               }
+
                off = constant_expr_alloc(&expr->location,
                                          expr_basetype(expr),
                                          BYTEORDER_HOST_ENDIAN,
@@ -549,7 +559,7 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
 
                rshift = binop_expr_alloc(&expr->location, OP_RSHIFT, and, off);
                rshift->dtype           = expr->dtype;
-               rshift->byteorder       = expr->byteorder;
+               rshift->byteorder       = byteorder;
                rshift->len             = masklen;
 
                *exprp = rshift;
index 9b85c75aca301bd95e2f1a8905a8417b0a543cf6..944208f2dde4b0210bee961d6d98a30f1a184c9c 100644 (file)
@@ -2,8 +2,8 @@
 ip6 test-ip6 output
   [ payload load 2b @ network header + 0 => reg 1 ]
   [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
-  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
   [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
   [ bitwise reg 1 = ( reg 1 << 0x00000002 ) ]
   [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
   [ ct set mark with reg 1 ]
@@ -12,8 +12,8 @@ ip6 test-ip6 output
 ip6 test-ip6 output
   [ payload load 2b @ network header + 0 => reg 1 ]
   [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
-  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
   [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
   [ bitwise reg 1 = ( reg 1 << 0x0000001a ) ]
   [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
   [ ct set mark with reg 1 ]
@@ -22,8 +22,8 @@ ip6 test-ip6 output
 ip6 test-ip6 output
   [ payload load 2b @ network header + 0 => reg 1 ]
   [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
-  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
   [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
   [ bitwise reg 1 = ( reg 1 & 0xfffffffb ) ^ 0x00000004 ]
   [ ct set mark with reg 1 ]
 
@@ -31,8 +31,8 @@ ip6 test-ip6 output
 ip6 test-ip6 output
   [ payload load 2b @ network header + 0 => reg 1 ]
   [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
-  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
   [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
   [ bitwise reg 1 = ( reg 1 & 0x00ffffff ) ^ 0xff000000 ]
   [ ct set mark with reg 1 ]
 
@@ -40,7 +40,7 @@ ip6 test-ip6 output
 ip6 test-ip6 output
   [ payload load 2b @ network header + 0 => reg 1 ]
   [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
-  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
   [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
   [ bitwise reg 1 = ( reg 1 & 0x0000003c ) ^ 0x00000000 ]
   [ ct set mark with reg 1 ]
index 379a9c133c4a611b4dc7a0944c9f0d92e1e27f16..6a37f1dee7edf8f5475c927f27dc75b2c831ac71 100644 (file)
@@ -65,8 +65,8 @@ ip6 test-ip6 input
 ip6 test-ip6 input
   [ payload load 2b @ network header + 0 => reg 1 ]
   [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
-  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
   [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
   [ bitwise reg 1 = ( reg 1 << 0x00000002 ) ]
   [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
   [ meta set mark with reg 1 ]
@@ -75,8 +75,8 @@ ip6 test-ip6 input
 ip6 test-ip6 input
   [ payload load 2b @ network header + 0 => reg 1 ]
   [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
-  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
   [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
   [ bitwise reg 1 = ( reg 1 << 0x0000001a ) ]
   [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
   [ meta set mark with reg 1 ]