diff options
author | Florian Westphal <fw@strlen.de> | 2016-04-15 15:09:39 +0200 |
---|---|---|
committer | Florian Westphal <fw@strlen.de> | 2016-04-19 15:23:20 +0200 |
commit | e20eac092725c982387181f3df557877b02eb345 (patch) | |
tree | bad4c5ba92918e470ea775692260fe772db5057e /src/payload.c | |
parent | c30fc3d731b711847fce7910e95d1c217886cb09 (diff) |
payload: only merge if adjacent and combined size fits into a register
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>
Diffstat (limited to 'src/payload.c')
-rw-r--r-- | src/payload.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/src/payload.c b/src/payload.c index 7e380617..f6c0a975 100644 --- a/src/payload.c +++ b/src/payload.c @@ -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; } /** |