]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
payload: only merge if adjacent and combined size fits into a register
authorFlorian Westphal <fw@strlen.de>
Fri, 15 Apr 2016 13:09:39 +0000 (15:09 +0200)
committerFlorian Westphal <fw@strlen.de>
Tue, 19 Apr 2016 13:23:20 +0000 (15:23 +0200)
add rule ip6 filter input ip6 saddr ::1/128 ip6 daddr ::1/128 fails,
we ask to compare a 32byte immediate which is not supported:

  [ payload load 32b @ network header + 8 => reg 1 ]
  [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x01000000 0x00000000 0x00000000 0x00000000 0x02000000 ]

We would need to use two cmps in this case, i.e.:

  [ payload load 32b @ network header + 8 => reg 1 ]
  [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x01000000 ]
  [ cmp eq reg 2 0x00000000 0x00000000 0x00000000 0x02000000 ]

Seems however that this requires a bit more changes to how nft
handles register allocations, we'd also need to undo the constant merge.

Lets disable merging for now so that we generate

  [ payload load 16b @ network header + 8 => reg 1 ]
  [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x01000000 ]
  [ payload load 16b @ network header + 24 => reg 1 ]
  [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x02000000 ]

... if merge would bring us over the 128 bit register size.

Closes: http://bugzilla.netfilter.org/show_bug.cgi?id=1032
Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/payload.h
src/payload.c
src/rule.c
tests/py/ip6/ip6.t
tests/py/ip6/ip6.t.payload.inet
tests/py/ip6/ip6.t.payload.ip6

index a19e6906badb7fc8d70fc23f981485ec960d25d0..fae3c673bbd74a279126b320b44e9d1fa10b4ad7 100644 (file)
@@ -17,7 +17,7 @@ extern int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
 extern int exthdr_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
                                  struct stmt **res);
 
-extern bool payload_is_adjacent(const struct expr *e1, const struct expr *e2);
+extern bool payload_can_merge(const struct expr *e1, const struct expr *e2);
 extern struct expr *payload_expr_join(const struct expr *e1,
                                      const struct expr *e2);
 
index 7e380617cfc708b4b50772a084eaf54d52b3ee2b..f6c0a975df77a1b173f10a4ab1eaf5a79969838b 100644 (file)
@@ -483,23 +483,36 @@ raw:
        list_add_tail(&new->list, list);
 }
 
+static bool payload_is_adjacent(const struct expr *e1, const struct expr *e2)
+{
+       if (e1->payload.base             == e2->payload.base &&
+           e1->payload.offset + e1->len == e2->payload.offset)
+               return true;
+       return false;
+}
+
 /**
- * payload_is_adjacent - return whether two payload expressions refer to
- *                      adjacent header locations
+ * payload_can_merge - return whether two payload expressions can be merged
  *
  * @e1:                first payload expression
  * @e2:                second payload expression
  */
-bool payload_is_adjacent(const struct expr *e1, const struct expr *e2)
+bool payload_can_merge(const struct expr *e1, const struct expr *e2)
 {
+       unsigned int total;
+
+       if (!payload_is_adjacent(e1, e2))
+               return false;
+
        if (e1->payload.offset % BITS_PER_BYTE || e1->len % BITS_PER_BYTE ||
            e2->payload.offset % BITS_PER_BYTE || e2->len % BITS_PER_BYTE)
                return false;
 
-       if (e1->payload.base             == e2->payload.base &&
-           e1->payload.offset + e1->len == e2->payload.offset)
-               return true;
-       return false;
+       total = e1->len + e2->len;
+       if (total < e1->len || total > (NFT_REG_SIZE * BITS_PER_BYTE))
+               return false;
+
+       return true;
 }
 
 /**
index b7f4a07fe132e7f145f0801f30bce2f440a3ba18..2fe67454497270400e5ce878ef03a06846a9e83f 100644 (file)
@@ -1292,7 +1292,7 @@ static void payload_do_merge(struct stmt *sa[], unsigned int n)
                stmt = sa[i];
                this = stmt->expr;
 
-               if (!payload_is_adjacent(last->left, this->left) ||
+               if (!payload_can_merge(last->left, this->left) ||
                    last->op != this->op) {
                        last = this;
                        j = i;
index 963667214a07ee5ebef46c7f73846b077a9f93ee..2a1eee783f4ee4f4f290bcd7d1f147762fd953a2 100644 (file)
@@ -139,6 +139,7 @@ ip6 saddr 1234::;ok
 # v61          ({v610}|{v611})
 # v60          (::)
 ip6 saddr ::/64;ok
+ip6 saddr ::1 ip6 daddr ::2;ok
 
 - ip6 daddr != {::1234:1234:1234:1234:1234:1234:1234, 1234:1234::1234:1234:1234:1234:1234 };ok
 ip6 daddr != ::1234:1234:1234:1234:1234:1234:1234-1234:1234::1234:1234:1234:1234:1234;ok;ip6 daddr != 0:1234:1234:1234:1234:1234:1234:1234-1234:1234:0:1234:1234:1234:1234:1234
index 4bafb26745746c7ec8cf164516d49da27e8cdef7..4d2ea3525446e32b936f6d9c4daed07414d3e383 100644 (file)
@@ -449,6 +449,15 @@ inet test-inet input
   [ bitwise reg 1 = (reg=1 & 0xffffffff 0xffffffff 0x00000000 0x00000000 ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
   [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x00000000 ]
 
+# ip6 saddr ::1 ip6 daddr ::2
+inet test-inet input
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x0000000a ]
+  [ payload load 16b @ network header + 8 => reg 1 ]
+  [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x01000000 ]
+  [ payload load 16b @ network header + 24 => reg 1 ]
+  [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x02000000 ]
+
 # ip6 daddr != ::1234:1234:1234:1234:1234:1234:1234-1234:1234::1234:1234:1234:1234:1234
 inet test-inet input
   [ meta load nfproto => reg 1 ]
index c6e856cc70ebba0cdedf5ff429de46b7548e12f1..db59bfbe1543ec95d427ec2fe5ec8476ee653303 100644 (file)
@@ -329,6 +329,13 @@ ip6 test-ip6 input
   [ bitwise reg 1 = (reg=1 & 0xffffffff 0xffffffff 0x00000000 0x00000000 ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
   [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x00000000 ]
 
+# ip6 saddr ::1 ip6 daddr ::2
+ip6 test-ip6 input
+  [ payload load 16b @ network header + 8 => reg 1 ]
+  [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x01000000 ]
+  [ payload load 16b @ network header + 24 => reg 1 ]
+  [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x02000000 ]
+
 # ip6 daddr != ::1234:1234:1234:1234:1234:1234:1234-1234:1234::1234:1234:1234:1234:1234
 ip6 test-ip6 input
   [ payload load 16b @ network header + 24 => reg 1 ]