mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net v2] udp_tunnel: fix GRO callback mismatch during setup
@ 2026-11-11 21:46 Jérémy Jean
  2026-11-11 21:51 ` netdev-bot+sinfo
  0 siblings, 1 reply; 3+ messages in thread
From: Jérémy Jean @ 2026-11-11 21:46 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman
  Cc: netdev, linux-kernel, Jérémy Jean, stable

setup_udp_tunnel_sock() updates an already bound socket. GRO can find it
while the socket callbacks and global static call disagree. Receive and
completion may then parse one packet differently and write out of bounds,
KASAN reports as:

  BUG: KASAN: slab-out-of-bounds in udp6_gro_complete+0x48a/0x4b0
  Write of size 2 at addr ffff8880044d8e78 by task repro/44

Publish gro_receive last and read it once. Count tunnel GRO receive
callbacks and consume one at each UDP completion. Only use the static
call if its target matches, and wait before changing it.

Fixes: 5d7f5b2f6b93 ("udp_tunnel: use static call for GRO hooks when possible")
Cc: stable@vger.kernel.org
Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr>
---

v1: https://lore.kernel.org/all/20260906211351.1272699-2-Jeremy.Jean@oss.cyber.gouv.fr/
Sashiko: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260906211351.1272699-2-Jeremy.Jean%40oss.cyber.gouv.fr

 include/net/gro.h          |  3 ++-
 net/core/gro.c             |  1 +
 net/ipv4/udp_offload.c     | 51 +++++++++++++++++++++++++++-----------
 net/ipv4/udp_tunnel_core.c |  5 ++--
 4 files changed, 42 insertions(+), 18 deletions(-)

diff --git a/include/net/gro.h b/include/net/gro.h
index 7a19d4486456..81bd838f268f 100644
--- a/include/net/gro.h
+++ b/include/net/gro.h
@@ -45,7 +45,8 @@ struct napi_gro_cb {
 	/* Used in ipv6_gro_receive() and foo-over-udp and esp-in-udp */
 	u16	proto;
 
-	u16	pad;
+	/* UDP tunnel GRO callbacks left to complete */
+	u16	udp_tunnel_gro_count;
 
 /* Used in napi_gro_cb::free */
 #define NAPI_GRO_FREE             1
diff --git a/net/core/gro.c b/net/core/gro.c
index 75f6a5f39a4b..96c3bbd6c153 100644
--- a/net/core/gro.c
+++ b/net/core/gro.c
@@ -526,6 +526,7 @@ static enum gro_result dev_gro_receive(struct gro_node *gro,
 	*(u32 *)&NAPI_GRO_CB(skb)->zeroed = 0;
 	NAPI_GRO_CB(skb)->flush = skb_has_frag_list(skb);
 	NAPI_GRO_CB(skb)->count = 1;
+	NAPI_GRO_CB(skb)->udp_tunnel_gro_count = 0;
 	if (unlikely(skb_is_gso(skb))) {
 		NAPI_GRO_CB(skb)->count = skb_shinfo(skb)->gso_segs;
 		/* Only support TCP and non DODGY users, with a sane gso_segs. */
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index cd9d7426b227..39f06fcd59ab 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -136,6 +136,7 @@ void udp_tunnel_update_gro_rcv(struct sock *sk, bool add)
 		static_branch_enable(&udp_tunnel_static_call);
 	} else if (old_gro_type_nr == 1) {
 		static_branch_disable(&udp_tunnel_static_call);
+		synchronize_net();
 		static_call_update(udp_tunnel_gro_rcv, dummy_gro_rcv);
 	}
 
@@ -144,27 +145,37 @@ void udp_tunnel_update_gro_rcv(struct sock *sk, bool add)
 }
 EXPORT_SYMBOL_GPL(udp_tunnel_update_gro_rcv);
 
-static struct sk_buff *udp_tunnel_gro_rcv(struct sock *sk,
+static struct sk_buff *udp_tunnel_gro_rcv(udp_tunnel_gro_receive_t gro_receive,
+					  struct sock *sk,
 					  struct list_head *head,
 					  struct sk_buff *skb)
 {
-	if (static_branch_likely(&udp_tunnel_static_call)) {
-		if (unlikely(gro_recursion_inc_test(skb))) {
-			NAPI_GRO_CB(skb)->flush |= 1;
-			return NULL;
-		}
-		return static_call(udp_tunnel_gro_rcv)(sk, head, skb);
+	if (unlikely(gro_recursion_inc_test(skb))) {
+		NAPI_GRO_CB(skb)->flush |= 1;
+		return NULL;
 	}
-	return call_gro_receive_sk(udp_sk(sk)->gro_receive, sk, head, skb);
+	NAPI_GRO_CB(skb)->udp_tunnel_gro_count++;
+
+	if (static_branch_likely(&udp_tunnel_static_call) &&
+	    likely(gro_receive == static_call_query(udp_tunnel_gro_rcv)))
+		return static_call(udp_tunnel_gro_rcv)(sk, head, skb);
+	return gro_receive(sk, head, skb);
 }
 
 #else
 
-static struct sk_buff *udp_tunnel_gro_rcv(struct sock *sk,
+static struct sk_buff *udp_tunnel_gro_rcv(udp_tunnel_gro_receive_t gro_receive,
+					  struct sock *sk,
 					  struct list_head *head,
 					  struct sk_buff *skb)
 {
-	return call_gro_receive_sk(udp_sk(sk)->gro_receive, sk, head, skb);
+	if (unlikely(gro_recursion_inc_test(skb))) {
+		NAPI_GRO_CB(skb)->flush |= 1;
+		return NULL;
+	}
+	NAPI_GRO_CB(skb)->udp_tunnel_gro_count++;
+
+	return gro_receive(sk, head, skb);
 }
 
 #endif
@@ -777,6 +788,7 @@ static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
 struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb,
 				struct udphdr *uh, struct sock *sk)
 {
+	udp_tunnel_gro_receive_t gro_receive = NULL;
 	struct sk_buff *pp = NULL;
 	struct sk_buff *p;
 	struct udphdr *uh2;
@@ -795,7 +807,11 @@ struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb,
 	 * cases. Such packets should be caught in udp_unexpected_gso later.
 	 */
 	NAPI_GRO_CB(skb)->is_flist = 0;
-	if (!sk || !udp_sk(sk)->gro_receive) {
+	if (sk) {
+		/* Pairs with smp_store_release() in setup_udp_tunnel_sock(). */
+		gro_receive = smp_load_acquire(&udp_sk(sk)->gro_receive);
+	}
+	if (!gro_receive) {
 		/* If the packet was locally encapsulated in a UDP tunnel that
 		 * wasn't detected above, do not GRO.
 		 */
@@ -842,7 +858,7 @@ struct sk_buff *udp_gro_receive(struct list_head *head, struct sk_buff *skb,
 
 	skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */
 	skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr));
-	pp = udp_tunnel_gro_rcv(sk, head, skb);
+	pp = udp_tunnel_gro_rcv(gro_receive, sk, head, skb);
 
 out:
 	skb_gro_flush_final(skb, pp, flush);
@@ -921,6 +937,7 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff,
 {
 	struct udphdr *uh = (struct udphdr *)(skb->data + nhoff);
 	unsigned int newlen = skb->len - nhoff;
+	udp_tunnel_gro_complete_t gro_complete = NULL;
 	struct sock *sk;
 	int err;
 
@@ -928,7 +945,12 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff,
 
 	sk = INDIRECT_CALL_INET(lookup, udp6_lib_lookup_skb,
 				udp4_lib_lookup_skb, skb, uh->source, uh->dest);
-	if (sk && udp_sk(sk)->gro_complete) {
+	if (NAPI_GRO_CB(skb)->udp_tunnel_gro_count) {
+		NAPI_GRO_CB(skb)->udp_tunnel_gro_count--;
+		if (sk)
+			gro_complete = READ_ONCE(udp_sk(sk)->gro_complete);
+	}
+	if (gro_complete) {
 		skb_shinfo(skb)->gso_type = uh->check ? SKB_GSO_UDP_TUNNEL_CSUM
 					: SKB_GSO_UDP_TUNNEL;
 
@@ -941,8 +963,7 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff,
 		 * functions to make them set up the inner offsets.
 		 */
 		skb->encapsulation = 1;
-		err = udp_sk(sk)->gro_complete(sk, skb,
-				nhoff + sizeof(struct udphdr));
+		err = gro_complete(sk, skb, nhoff + sizeof(struct udphdr));
 	} else {
 		err = udp_gro_complete_segment(skb);
 	}
diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c
index a128fe85620d..147c92374975 100644
--- a/net/ipv4/udp_tunnel_core.c
+++ b/net/ipv4/udp_tunnel_core.c
@@ -84,8 +84,9 @@ void setup_udp_tunnel_sock(struct net *net, struct sock *sk,
 	udp_sk(sk)->encap_err_rcv = cfg->encap_err_rcv;
 	udp_sk(sk)->encap_err_lookup = cfg->encap_err_lookup;
 	udp_sk(sk)->encap_destroy = cfg->encap_destroy;
-	udp_sk(sk)->gro_receive = cfg->gro_receive;
-	udp_sk(sk)->gro_complete = cfg->gro_complete;
+	WRITE_ONCE(udp_sk(sk)->gro_complete, cfg->gro_complete);
+	/* Pairs with smp_load_acquire() in udp_gro_receive(). */
+	smp_store_release(&udp_sk(sk)->gro_receive, cfg->gro_receive);
 
 	udp_tunnel_encap_enable(sk);
 
-- 
2.47.3


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

* Re: [PATCH net v2] udp_tunnel: fix GRO callback mismatch during setup
  2026-11-11 21:46 [PATCH net v2] udp_tunnel: fix GRO callback mismatch during setup Jérémy Jean
@ 2026-11-11 21:51 ` netdev-bot+sinfo
  2026-11-11 21:58   ` Jérémy Jean
  0 siblings, 1 reply; 3+ messages in thread
From: netdev-bot+sinfo @ 2026-11-11 21:51 UTC (permalink / raw)
  To: Jérémy Jean
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, netdev, linux-kernel, stable

Hi!

This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:

 - How the issue was discovered, e.g. hit in production, hit during
   development, syzbot report, manual code inspection, LLM or static
   analysis tool scan.

Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.

The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.

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

* Re: [PATCH net v2] udp_tunnel: fix GRO callback mismatch during setup
  2026-11-11 21:51 ` netdev-bot+sinfo
@ 2026-11-11 21:58   ` Jérémy Jean
  0 siblings, 0 replies; 3+ messages in thread
From: Jérémy Jean @ 2026-11-11 21:58 UTC (permalink / raw)
  To: netdev-bot+sinfo
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, netdev, linux-kernel, stable

On 2026-11-11 22:51, netdev-bot+sinfo@kernel.org wrote:
> Hi!
> 
> This is an automated message. This series looks like a fix, but its
> commit messages seem to be missing some information:
> 
>  - How the issue was discovered, e.g. hit in production, hit during
>    development, syzbot report, manual code inspection, LLM or static
>    analysis tool scan.
> 
> Please do not repost the series just to address the above. Instead,
> reply to this email with the missing information, so that reviewers
> can take it into account. If the series needs another revision for
> other reasons, please include the information in the commit messages
> then.
> 
> The evaluation is done by an LLM so it may be wrong, if you think
> that is the case please reply and explain.

The bug was discovered by code inspection assisted by LLM.

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

end of thread, other threads:[~2026-11-11 21:58 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-11 21:46 [PATCH net v2] udp_tunnel: fix GRO callback mismatch during setup Jérémy Jean
2026-11-11 21:51 ` netdev-bot+sinfo
2026-11-11 21:58   ` Jérémy Jean

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®