]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
netlink_delinearize: zero shift removal
authorFlorian Westphal <fw@strlen.de>
Fri, 3 Dec 2021 19:19:10 +0000 (20:19 +0100)
committerFlorian Westphal <fw@strlen.de>
Thu, 9 Dec 2021 10:12:32 +0000 (11:12 +0100)
Remove shifts-by-0.  These can occur after binop postprocessing
has adjusted the RHS value to account for a mask operation.

Example: frag frag-off @s4

Is internally represented via:

  [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
  [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
  [ bitwise reg 1 = ( reg 1 >> 0x00000003 ) ]
  [ lookup reg 1 set s ]

First binop masks out unwanted parts of the 16-bit field.
Second binop needs to left-shift so that lookups in the set will work.

When decoding, the first binop is removed after the exthdr load
has been adjusted accordingly.  Constant propagation adjusts the
shift-value to 0 on removal.  This change then gets rid of the
shift-by-0 entirely.

After this change, 'frag frag-off @s4' input is shown as-is.

Signed-off-by: Florian Westphal <fw@strlen.de>
src/netlink_delinearize.c
tests/shell/testcases/sets/dumps/typeof_sets_0.nft
tests/shell/testcases/sets/typeof_sets_0

index e37a34f37ba29f81c87e3b60b1fe48123b22128e..323e9150cdf6f3213ca66151913cd2d8dbe645e2 100644 (file)
@@ -2322,6 +2322,20 @@ static void map_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr)
                binop_postprocess(ctx, expr, &expr->map);
 }
 
+static bool is_shift_by_zero(const struct expr *binop)
+{
+       struct expr *rhs;
+
+       if (binop->op != OP_RSHIFT && binop->op != OP_LSHIFT)
+               return false;
+
+       rhs = binop->right;
+       if (rhs->etype != EXPR_VALUE || rhs->len > 64)
+               return false;
+
+       return mpz_get_uint64(rhs->value) == 0;
+}
+
 static void relational_binop_postprocess(struct rule_pp_ctx *ctx,
                                         struct expr **exprp)
 {
@@ -2421,6 +2435,13 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx,
                 */
 
                binop_postprocess(ctx, binop, &binop->left);
+               if (is_shift_by_zero(binop)) {
+                       struct expr *lhs = binop->left;
+
+                       expr_get(lhs);
+                       expr_free(binop);
+                       expr->left = lhs;
+               }
        }
 }
 
index ad442713f6dc89aeac795ae7b4a35f648c8472ed..e397a63454625b4c63c2076107bb707ce14bb5d7 100644 (file)
@@ -53,6 +53,10 @@ table inet t {
                vlan id @s2 accept
        }
 
+       chain c4 {
+               frag frag-off @s4 accept
+       }
+
        chain c5 {
                ip option ra value @s5 accept
        }
@@ -65,6 +69,10 @@ table inet t {
                sctp chunk init num-inbound-streams @s7 accept
        }
 
+       chain c8 {
+               ip version @s8 accept
+       }
+
        chain c9 {
                ip hdrlength @s9 accept
        }
index 2102789e104345bd8e4c77408a1ba3bcd55eacb1..be906cdcc8421189840fe5d42b07ba908b9c5794 100755 (executable)
@@ -58,6 +58,10 @@ EXPECTED="table inet t {
                ether type vlan vlan id @s2 accept
        }
 
+       chain c4 {
+               frag frag-off @s4 accept
+       }
+
        chain c5 {
                ip option ra value @s5 accept
        }
@@ -70,6 +74,10 @@ EXPECTED="table inet t {
                sctp chunk init num-inbound-streams @s7 accept
        }
 
+       chain c8 {
+               ip version @s8 accept
+       }
+
        chain c9 {
                ip hdrlength @s9 accept
        }