All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net] netfilter: nft_payload: move offset bounds check outside csum condition
@ 2026-05-28 13:39 Siho Lee
  2026-05-28 14:12 ` Florian Westphal
  0 siblings, 1 reply; 3+ messages in thread
From: Siho Lee @ 2026-05-28 13:39 UTC (permalink / raw)
  To: Pablo Neira Ayuso, Florian Westphal; +Cc: netfilter-devel, netdev, stable

From 574604a1b4a98ee130d7f727ad3c8a7df3f3b6f1 Mon Sep 17 00:00:00 2001
From: Siho Lee <25esihoya@gmail.com>
Date: Thu, 28 May 2026 22:39:03 +0900
Subject: [PATCH v1] netfilter: nft_payload: move offset bounds check outside
 csum condition

The bounds check for offset + priv->len was placed inside the csum
condition block. When csum_type is NFT_PAYLOAD_CSUM_NONE and
csum_flags is 0, the entire block including the bounds check is
skipped.

For NFT_PAYLOAD_LL_HEADER, offset is computed as:
    offset = skb_mac_header(skb) - skb->data - vlan_hlen
which evaluates to -14 (or -18 with VLAN) after eth_type_trans()
pulls the Ethernet header.

Without the bounds check, a negative offset reaches:
    skb_ensure_writable(skb, max(offset + priv->len, 0))
    skb_store_bits(skb, offset, src, priv->len)

max(-14 + 4, 0) == 0 makes skb_ensure_writable a no-op, and
skb_store_bits(skb, -14, ...) writes to skb headroom (OOB write).

The signed-unsigned comparison in the bounds check correctly catches
negative offsets: (unsigned int)(-10) is a large positive value that
exceeds any valid skb->len.

Move the bounds check outside the csum condition so it applies
regardless of csum_type/csum_flags.

Fixes: d5953d680f7e ("netfilter: nft_payload: sanitize offset and
length before calling skb_checksum()")
Cc: stable@vger.kernel.org
Signed-off-by: Siho Lee <25esihoya@gmail.com>
---
 net/netfilter/nft_payload.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
index 01e13e5255a9..62661e4eeb13 100644
--- a/net/netfilter/nft_payload.c
+++ b/net/netfilter/nft_payload.c
@@ -873,13 +873,13 @@ static void nft_payload_set_eval(const struct
nft_expr *expr,
 	csum_offset = offset + priv->csum_offset;
 	offset += priv->offset;

+	if (offset + priv->len > skb->len)
+		goto err;
+
 	if ((priv->csum_type == NFT_PAYLOAD_CSUM_INET || priv->csum_flags) &&
 	    ((priv->base != NFT_PAYLOAD_TRANSPORT_HEADER &&
 	      priv->base != NFT_PAYLOAD_INNER_HEADER) ||
 	     skb->ip_summed != CHECKSUM_PARTIAL)) {
-		if (offset + priv->len > skb->len)
-			goto err;
-
 		fsum = skb_checksum(skb, offset, priv->len, 0);
 		tsum = csum_partial(src, priv->len, 0);

-- 
2.43.0

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

* Re: [PATCH net] netfilter: nft_payload: move offset bounds check outside csum condition
  2026-05-28 13:39 [PATCH net] netfilter: nft_payload: move offset bounds check outside csum condition Siho Lee
@ 2026-05-28 14:12 ` Florian Westphal
  2026-05-28 15:28   ` [PATCH v2 net] netfilter: nft_payload: validate offset for all csum_type paths Siho Lee
  0 siblings, 1 reply; 3+ messages in thread
From: Florian Westphal @ 2026-05-28 14:12 UTC (permalink / raw)
  To: Siho Lee; +Cc: Pablo Neira Ayuso, netfilter-devel, netdev, stable

Siho Lee <25esihoya@gmail.com> wrote:
> From 574604a1b4a98ee130d7f727ad3c8a7df3f3b6f1 Mon Sep 17 00:00:00 2001
> From: Siho Lee <25esihoya@gmail.com>
> Date: Thu, 28 May 2026 22:39:03 +0900
> Subject: [PATCH v1] netfilter: nft_payload: move offset bounds check outside
>  csum condition
> 
> The bounds check for offset + priv->len was placed inside the csum
> condition block. When csum_type is NFT_PAYLOAD_CSUM_NONE and
> csum_flags is 0, the entire block including the bounds check is
> skipped.
> 
> For NFT_PAYLOAD_LL_HEADER, offset is computed as:
>     offset = skb_mac_header(skb) - skb->data - vlan_hlen
> which evaluates to -14 (or -18 with VLAN) after eth_type_trans()
> pulls the Ethernet header.
> 
> Without the bounds check, a negative offset reaches:
>     skb_ensure_writable(skb, max(offset + priv->len, 0))
>     skb_store_bits(skb, offset, src, priv->len)
> 
> max(-14 + 4, 0) == 0 makes skb_ensure_writable a no-op, and
> skb_store_bits(skb, -14, ...) writes to skb headroom (OOB write).
> 
> The signed-unsigned comparison in the bounds check correctly catches
> negative offsets: (unsigned int)(-10) is a large positive value that
> exceeds any valid skb->len.
> 
> Move the bounds check outside the csum condition so it applies
> regardless of csum_type/csum_flags.

This breaks link layer update support.

# cd git/nftables/tests/shell
# NFT=nft ./run-tests.sh testcases/packetpath/bridge_pass_up C
W: [FAILED]     1/1 testcases/packetpath/bridge_pass_up

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

* [PATCH v2 net] netfilter: nft_payload: validate offset for all csum_type paths
  2026-05-28 14:12 ` Florian Westphal
@ 2026-05-28 15:28   ` Siho Lee
  0 siblings, 0 replies; 3+ messages in thread
From: Siho Lee @ 2026-05-28 15:28 UTC (permalink / raw)
  To: Pablo Neira Ayuso, Florian Westphal; +Cc: netfilter-devel, netdev, stable

From e11e35dfd10960ea8ca4258dfa6ed7aeb207179f Mon Sep 17 00:00:00 2001
From: Siho Lee <25esihoya@gmail.com>
Date: Fri, 29 May 2026 00:23:35 +0900
Subject: [PATCH v2] netfilter: nft_payload: validate offset for all csum_type
 paths

When csum_type is NFT_PAYLOAD_CSUM_NONE and csum_flags is 0, the
bounds check inside the csum condition block is skipped entirely.

For NFT_PAYLOAD_LL_HEADER, offset is computed as:
    offset = skb_mac_header(skb) - skb->data - vlan_hlen
which evaluates to -14 (or -18 with VLAN) after eth_type_trans()
pulls the Ethernet header. This is a valid negative offset that
refers to the Ethernet header area (used by bridge/vlan rules).

However, without any bounds check in the csum=NONE path:
- skb_ensure_writable(skb, max(offset + priv->len, 0)):
  max() converts negative values to 0, making it a no-op.
- skb_store_bits(skb, offset, src, priv->len):
  A negative offset that exceeds skb headroom writes out of bounds.

Add proper validation after the csum condition block:
- Negative offsets: ensure they fall within skb_headroom(skb)
  (bridge/vlan rules legitimately access the Ethernet header)
- Positive offsets: ensure offset + len does not exceed skb->len

Also remove the max() wrapper from skb_ensure_writable() since
the new validation guarantees the offset is within range.

Fixes: d5953d680f7e ("netfilter: nft_payload: sanitize offset and
length before calling skb_checksum()")
Cc: stable@vger.kernel.org
Signed-off-by: Siho Lee <25esihoya@gmail.com>
---
 net/netfilter/nft_payload.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
index 01e13e5255a9..2c891c13bbf5 100644
--- a/net/netfilter/nft_payload.c
+++ b/net/netfilter/nft_payload.c
@@ -892,7 +892,17 @@ static void nft_payload_set_eval(const struct
nft_expr *expr,
 			goto err;
 	}

-	if (skb_ensure_writable(skb, max(offset + priv->len, 0)) ||
+	/* Negative offset (LL_HEADER with bridge/vlan) must be within headroom.
+	 * Positive offset must be within skb length.
+	 */
+	if (offset < 0) {
+		if (-offset > (int)skb_headroom(skb))
+			goto err;
+	} else if (offset + priv->len > skb->len) {
+		goto err;
+	}
+
+	if (skb_ensure_writable(skb, offset + priv->len) ||
 	    skb_store_bits(skb, offset, src, priv->len) < 0)
 		goto err;

-- 
2.43.0

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

end of thread, other threads:[~2026-05-28 15:28 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-28 13:39 [PATCH net] netfilter: nft_payload: move offset bounds check outside csum condition Siho Lee
2026-05-28 14:12 ` Florian Westphal
2026-05-28 15:28   ` [PATCH v2 net] netfilter: nft_payload: validate offset for all csum_type paths Siho Lee

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.