diff options
author | Florian Westphal <fw@strlen.de> | 2017-08-16 17:41:30 +0200 |
---|---|---|
committer | Florian Westphal <fw@strlen.de> | 2017-08-17 12:29:03 +0200 |
commit | 63c504cd3c0dbecbe226fbef970e700130367214 (patch) | |
tree | 76ae11162d0c7295d34c41e4fc5f6849108b96f3 | |
parent | 7421aec47f81d3e4180648bf4ce84a8d49ea85cb (diff) |
evaluate: shift immediate value when adjusting size for csum fixup
nft add rule .. ip ttl set 64
erronously mangles ip protocol instead of ttl.
Because the kernel can't deal with odd-sized data (ttl is one byte) when
doing checksum fixups, so the write to 'ttl' is turned into
[ payload load 2b @ network header + 8 => reg 1 ]
[ bitwise reg 1 = (reg=1 & 0x000000ff ) ^ $new_value ]
[ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x0 ]
While doing so, we did fail to shift the imm value, i.e.
we clear the wrong half of the u16 (protocol) instead of csum.
The correct mask is 0xff00, and $new_value needs to be shifted
so we leave the protocol value (which is next to ttl) alone.
Fixes: f9069cefdf ("netlink: make checksum fixup work with odd-sized header fields")
Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | src/evaluate.c | 25 |
1 files changed, 14 insertions, 11 deletions
diff --git a/src/evaluate.c b/src/evaluate.c index 0fad0913..f52a0843 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1869,6 +1869,20 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt) shift_imm = expr_offset_shift(payload, payload->payload.offset, &extra_len); + payload_byte_size = round_up(payload->len, BITS_PER_BYTE) / BITS_PER_BYTE; + payload_byte_size += (extra_len / BITS_PER_BYTE); + + if (need_csum && payload_byte_size & 1) { + payload_byte_size++; + + if (payload_byte_offset & 1) { /* prefer 16bit aligned fetch */ + payload_byte_offset--; + assert(payload->payload.offset >= BITS_PER_BYTE); + } else { + shift_imm += BITS_PER_BYTE; + } + } + if (shift_imm) { struct expr *off; @@ -1885,17 +1899,6 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt) stmt->payload.val = binop; } - payload_byte_size = round_up(payload->len, BITS_PER_BYTE) / BITS_PER_BYTE; - payload_byte_size += (extra_len / BITS_PER_BYTE); - - if (need_csum && payload_byte_size & 1) { - payload_byte_size++; - - if (payload_byte_offset & 1) { /* prefer 16bit aligned fetch */ - payload_byte_offset--; - assert(payload->payload.offset >= BITS_PER_BYTE); - } - } masklen = payload_byte_size * BITS_PER_BYTE; mpz_init_bitmask(ff, masklen); |