summaryrefslogtreecommitdiffstats
path: root/src/evaluate.c
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2017-08-16 17:41:30 +0200
committerFlorian Westphal <fw@strlen.de>2017-08-17 12:29:03 +0200
commit63c504cd3c0dbecbe226fbef970e700130367214 (patch)
tree76ae11162d0c7295d34c41e4fc5f6849108b96f3 /src/evaluate.c
parent7421aec47f81d3e4180648bf4ce84a8d49ea85cb (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>
Diffstat (limited to 'src/evaluate.c')
-rw-r--r--src/evaluate.c25
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);