All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nf v2] netfilter: nft_bitwise: fix dst corruption in same register shifts
@ 2026-04-23 12:05 Fernando Fernandez Mancera
  2026-04-23 12:27 ` Florian Westphal
  0 siblings, 1 reply; 6+ messages in thread
From: Fernando Fernandez Mancera @ 2026-04-23 12:05 UTC (permalink / raw)
  To: netfilter-devel
  Cc: coreteam, jeremy, phil, fw, pablo, Fernando Fernandez Mancera

In nft_bitwise_eval_lshift() and nft_bitwise_eval_rshift(), shift
operations are performed in a loop over 32-bit words. The loop
calculates the shifted value, writes it to dst, and calculates the carry
from src for the next iteration.

If the source and destination registers overlap either exactly (sreg ==
dreg) or partially (e.g., dreg is offset from sreg by 4 bytes) the loop
overwrites src data before it can be read by subsequent iterations. This
causes the carry or the shifted data itself to be incorrectly calculated
using the newly modified dst value instead of the original src payload.

Fix this by separating the calculation and assignment phases. Evaluate
the shift into a temporary local array and then copy the final results
into dst. This completely decouples the memory reads from the memory
writes, safely supporting any register overlap configuration without
corrupting the payload.

This was tested for both partial and exact overlaps with the following
bytecode:

table test_table ip flags 0 use 1 handle 1
ip test_table test_chain use 3 type filter hook input prio 0 policy accept packets 0 bytes 0 flags 1
ip test_table test_chain 2
  [ immediate reg 1 0xaaaaaaaa 0x44332211 0x88776655 ]
  [ bitwise reg 1 = ( reg 9 << 0x08000000 ) ]
  [ cmp eq reg 1 0x55008877 0x00887766 ]
  [ counter pkts 0 bytes 0 ]
ip test_table test_chain 3 2
  [ immediate reg 1 0xaaaaaaaa 0x44332211 0x88776655 ]
  [ bitwise reg 1 = ( reg 9 << 0x08000000 ) ]
  [ cmp eq reg 1 0x55443322 0x00887766 ]
  [ counter pkts 1511 bytes 133128 ]
ip test_table test_chain 4 3
  [ immediate reg 1 0x44332211 0x88776655 ]
  [ bitwise reg 1 = ( reg 1 << 0x08000000 ) ]
  [ cmp eq reg 1 0x55443322 0x00887766 ]
  [ counter pkts 109 bytes 9548 ]
ip test_table test_chain 5 4
  [ immediate reg 1 0x44332211 0x88776655 ]
  [ bitwise reg 1 = ( reg 1 << 0x08000000 ) ]
  [ cmp eq reg 1 0x66443322 0x00887766 ]
  [ counter pkts 0 bytes 0 ]

Fixes: 567d746b55bc ("netfilter: bitwise: add support for shifts.")
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
---
v2: handle partially register overlap too
---
 net/netfilter/nft_bitwise.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
index 13808e9cd999..27fc09ec0e11 100644
--- a/net/netfilter/nft_bitwise.c
+++ b/net/netfilter/nft_bitwise.c
@@ -38,27 +38,35 @@ static void nft_bitwise_eval_mask_xor(u32 *dst, const u32 *src,
 static void nft_bitwise_eval_lshift(u32 *dst, const u32 *src,
 				    const struct nft_bitwise *priv)
 {
+	unsigned int i, n = DIV_ROUND_UP(priv->len, sizeof(u32));
 	u32 shift = priv->data.data[0];
-	unsigned int i;
+	u32 res[NFT_REG_SIZE];
 	u32 carry = 0;
 
-	for (i = DIV_ROUND_UP(priv->len, sizeof(u32)); i > 0; i--) {
-		dst[i - 1] = (src[i - 1] << shift) | carry;
+	for (i = n; i > 0; i--) {
+		res[i - 1] = (src[i - 1] << shift) | carry;
 		carry = src[i - 1] >> (BITS_PER_TYPE(u32) - shift);
 	}
+
+	for (i = 0; i < n; i++)
+		dst[i] = res[i];
 }
 
 static void nft_bitwise_eval_rshift(u32 *dst, const u32 *src,
 				    const struct nft_bitwise *priv)
 {
+	unsigned int i, n = DIV_ROUND_UP(priv->len, sizeof(u32));
 	u32 shift = priv->data.data[0];
-	unsigned int i;
+	u32 res[NFT_REG_SIZE];
 	u32 carry = 0;
 
-	for (i = 0; i < DIV_ROUND_UP(priv->len, sizeof(u32)); i++) {
-		dst[i] = carry | (src[i] >> shift);
+	for (i = 0; i < n; i++) {
+		res[i] = carry | (src[i] >> shift);
 		carry = src[i] << (BITS_PER_TYPE(u32) - shift);
 	}
+
+	for (i = 0; i < n; i++)
+		dst[i] = res[i];
 }
 
 static void nft_bitwise_eval_and(u32 *dst, const u32 *src, const u32 *src2,
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-04-23 14:51 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-23 12:05 [PATCH nf v2] netfilter: nft_bitwise: fix dst corruption in same register shifts Fernando Fernandez Mancera
2026-04-23 12:27 ` Florian Westphal
2026-04-23 12:34   ` Fernando Fernandez Mancera
2026-04-23 12:38     ` Florian Westphal
2026-04-23 14:49       ` Pablo Neira Ayuso
2026-04-23 14:50         ` Fernando Fernandez Mancera

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.