Netdev List
 help / color / mirror / Atom feed
* [PATCH 6.12.y v2] ipv4: start using dst_dev_rcu()
@ 2026-08-21  9:54 Miguel Gazquez (Schneider Electric)
  2026-08-24  9:05 ` Greg KH
  0 siblings, 1 reply; 3+ messages in thread
From: Miguel Gazquez (Schneider Electric) @ 2026-08-21  9:54 UTC (permalink / raw)
  To: stable, Eric Dumazet, David S. Miller, David Ahern,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Martin KaFai Lau,
	Wei Wang
  Cc: thomas.petazzoni, netdev, linux-kernel,
	Miguel Gazquez (Schneider Electric), Miguel Gazquez

From: Eric Dumazet <edumazet@google.com>

[ Upstream commit 6ad8de3cefdb6ffa6708b21c567df0dbf82c43a8 ]

Change icmpv4_xrlim_allow(), ip_defrag() to prevent possible UAF.

Change ipmr_prepare_xmit(), ipmr_queue_fwd_xmit(), ip_mr_output(),
ipv4_neigh_lookup() to use lockdep enabled dst_dev_rcu().

[ minor modifications to fix conflict , added rcu_read_lock and unlock
to ip_defrag function ]

Fixes: 4a6ce2b6f2ec ("net: introduce a new function dst_dev_put()")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://patch.msgid.link/20250828195823.3958522-9-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Miguel Gazquez (Schneider Electric) <miguel.gazquez@bootlin.com>
---
Signed-off-by: Miguel Gazquez <miguel.gazquez@bootlin.com>
---
Changes in v2:
- Added rcu_read_lock and unlock to ip_defrag function
- Link to v1: https://patch.msgid.link/20260820-cve-2025-40074-v1-1-f045d5f74950@bootlin.com
---
 net/ipv4/icmp.c        | 6 +++---
 net/ipv4/ip_fragment.c | 9 +++++++--
 net/ipv4/ipmr.c        | 4 ++--
 net/ipv4/route.c       | 4 ++--
 4 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index c7af8b914e13..1fc967a60bb9 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -320,17 +320,17 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
 		return true;
 
 	/* No rate limit on loopback */
-	dev = dst_dev(dst);
+	rcu_read_lock();
+	dev = dst_dev_rcu(dst);
 	if (dev && (dev->flags & IFF_LOOPBACK))
 		goto out;
 
-	rcu_read_lock();
 	peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr,
 			       l3mdev_master_ifindex_rcu(dev));
 	rc = inet_peer_xrlim_allow(peer,
 				   READ_ONCE(net->ipv4.sysctl_icmp_ratelimit));
-	rcu_read_unlock();
 out:
+	rcu_read_unlock();
 	if (!rc)
 		__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST);
 	else
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index d3abc84a6c02..f8919b2543e1 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -483,13 +483,16 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
 /* Process an incoming IP datagram fragment. */
 int ip_defrag(struct net *net, struct sk_buff *skb, u32 user)
 {
-	struct net_device *dev = skb->dev ? : skb_dst_dev(skb);
-	int vif = l3mdev_master_ifindex_rcu(dev);
+	struct net_device *dev;
 	struct ipq *qp;
+	int vif;
 
 	__IP_INC_STATS(net, IPSTATS_MIB_REASMREQDS);
 
 	/* Lookup (or create) queue header */
+	rcu_read_lock();
+	dev = skb->dev ? : skb_dst_dev_rcu(skb);
+	vif = l3mdev_master_ifindex_rcu(dev);
 	qp = ip_find(net, ip_hdr(skb), user, vif);
 	if (qp) {
 		int ret;
@@ -499,9 +502,11 @@ int ip_defrag(struct net *net, struct sk_buff *skb, u32 user)
 		ret = ip_frag_queue(qp, skb);
 
 		spin_unlock(&qp->q.lock);
+		rcu_read_unlock();
 		ipq_put(qp);
 		return ret;
 	}
+	rcu_read_unlock();
 
 	__IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS);
 	kfree_skb(skb);
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index de0d9cc7806a..ad0b922ebc73 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1906,7 +1906,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
 		goto out_free;
 	}
 
-	encap += LL_RESERVED_SPACE(dev) + rt->dst.header_len;
+	encap += LL_RESERVED_SPACE(dst_dev_rcu(&rt->dst)) + rt->dst.header_len;
 
 	if (skb_cow(skb, encap)) {
 		ip_rt_put(rt);
@@ -1943,7 +1943,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
 	 * result in receiving multiple packets.
 	 */
 	NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD,
-		net, NULL, skb, skb->dev, dev,
+		net, NULL, skb, skb->dev, dst_dev_rcu(&rt->dst),
 		ipmr_forward_finish);
 	return;
 
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 4dce0de6ab89..0f31ae4da3d9 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -413,11 +413,11 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
 					   const void *daddr)
 {
 	const struct rtable *rt = container_of(dst, struct rtable, dst);
-	struct net_device *dev = dst_dev(dst);
+	struct net_device *dev;
 	struct neighbour *n;
 
 	rcu_read_lock();
-
+	dev = dst_dev_rcu(dst);
 	if (likely(rt->rt_gw_family == AF_INET)) {
 		n = ip_neigh_gw4(dev, rt->rt_gw4);
 	} else if (rt->rt_gw_family == AF_INET6) {

---
base-commit: 7155f3c7a69b8480e785f2a4252d31df95daa8d1
change-id: 20260820-cve-2025-40074-b2b8c05342a1

Best regards,
--  
Miguel Gazquez (Schneider Electric) <miguel.gazquez@bootlin.com>


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

* Re: [PATCH 6.12.y v2] ipv4: start using dst_dev_rcu()
  2026-08-21  9:54 [PATCH 6.12.y v2] ipv4: start using dst_dev_rcu() Miguel Gazquez (Schneider Electric)
@ 2026-08-24  9:05 ` Greg KH
  2026-08-25 11:49   ` Sasha Levin
  0 siblings, 1 reply; 3+ messages in thread
From: Greg KH @ 2026-08-24  9:05 UTC (permalink / raw)
  To: Miguel Gazquez (Schneider Electric)
  Cc: stable, Eric Dumazet, David S. Miller, David Ahern,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Martin KaFai Lau,
	Wei Wang, thomas.petazzoni, netdev, linux-kernel

On Fri, Aug 21, 2026 at 11:54:04AM +0200, Miguel Gazquez (Schneider Electric) wrote:
> From: Eric Dumazet <edumazet@google.com>
> 
> [ Upstream commit 6ad8de3cefdb6ffa6708b21c567df0dbf82c43a8 ]
> 
> Change icmpv4_xrlim_allow(), ip_defrag() to prevent possible UAF.
> 
> Change ipmr_prepare_xmit(), ipmr_queue_fwd_xmit(), ip_mr_output(),
> ipv4_neigh_lookup() to use lockdep enabled dst_dev_rcu().
> 
> [ minor modifications to fix conflict , added rcu_read_lock and unlock
> to ip_defrag function ]
> 
> Fixes: 4a6ce2b6f2ec ("net: introduce a new function dst_dev_put()")
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> Reviewed-by: David Ahern <dsahern@kernel.org>
> Link: https://patch.msgid.link/20250828195823.3958522-9-edumazet@google.com
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> Signed-off-by: Miguel Gazquez (Schneider Electric) <miguel.gazquez@bootlin.com>
> ---
> Signed-off-by: Miguel Gazquez <miguel.gazquez@bootlin.com>
> ---
> Changes in v2:
> - Added rcu_read_lock and unlock to ip_defrag function
> - Link to v1: https://patch.msgid.link/20260820-cve-2025-40074-v1-1-f045d5f74950@bootlin.com
> ---
>  net/ipv4/icmp.c        | 6 +++---
>  net/ipv4/ip_fragment.c | 9 +++++++--
>  net/ipv4/ipmr.c        | 4 ++--
>  net/ipv4/route.c       | 4 ++--
>  4 files changed, 14 insertions(+), 9 deletions(-)
> 
> diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
> index c7af8b914e13..1fc967a60bb9 100644
> --- a/net/ipv4/icmp.c
> +++ b/net/ipv4/icmp.c
> @@ -320,17 +320,17 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
>  		return true;
>  
>  	/* No rate limit on loopback */
> -	dev = dst_dev(dst);
> +	rcu_read_lock();
> +	dev = dst_dev_rcu(dst);
>  	if (dev && (dev->flags & IFF_LOOPBACK))
>  		goto out;
>  
> -	rcu_read_lock();
>  	peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr,
>  			       l3mdev_master_ifindex_rcu(dev));
>  	rc = inet_peer_xrlim_allow(peer,
>  				   READ_ONCE(net->ipv4.sysctl_icmp_ratelimit));
> -	rcu_read_unlock();
>  out:
> +	rcu_read_unlock();
>  	if (!rc)
>  		__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST);
>  	else
> diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
> index d3abc84a6c02..f8919b2543e1 100644
> --- a/net/ipv4/ip_fragment.c
> +++ b/net/ipv4/ip_fragment.c
> @@ -483,13 +483,16 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *skb,
>  /* Process an incoming IP datagram fragment. */
>  int ip_defrag(struct net *net, struct sk_buff *skb, u32 user)
>  {
> -	struct net_device *dev = skb->dev ? : skb_dst_dev(skb);
> -	int vif = l3mdev_master_ifindex_rcu(dev);
> +	struct net_device *dev;
>  	struct ipq *qp;
> +	int vif;
>  
>  	__IP_INC_STATS(net, IPSTATS_MIB_REASMREQDS);
>  
>  	/* Lookup (or create) queue header */
> +	rcu_read_lock();
> +	dev = skb->dev ? : skb_dst_dev_rcu(skb);
> +	vif = l3mdev_master_ifindex_rcu(dev);
>  	qp = ip_find(net, ip_hdr(skb), user, vif);
>  	if (qp) {
>  		int ret;
> @@ -499,9 +502,11 @@ int ip_defrag(struct net *net, struct sk_buff *skb, u32 user)
>  		ret = ip_frag_queue(qp, skb);
>  
>  		spin_unlock(&qp->q.lock);
> +		rcu_read_unlock();
>  		ipq_put(qp);
>  		return ret;
>  	}
> +	rcu_read_unlock();
>  
>  	__IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS);
>  	kfree_skb(skb);
> diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
> index de0d9cc7806a..ad0b922ebc73 100644
> --- a/net/ipv4/ipmr.c
> +++ b/net/ipv4/ipmr.c
> @@ -1906,7 +1906,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
>  		goto out_free;
>  	}
>  
> -	encap += LL_RESERVED_SPACE(dev) + rt->dst.header_len;
> +	encap += LL_RESERVED_SPACE(dst_dev_rcu(&rt->dst)) + rt->dst.header_len;
>  
>  	if (skb_cow(skb, encap)) {
>  		ip_rt_put(rt);
> @@ -1943,7 +1943,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
>  	 * result in receiving multiple packets.
>  	 */
>  	NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD,
> -		net, NULL, skb, skb->dev, dev,
> +		net, NULL, skb, skb->dev, dst_dev_rcu(&rt->dst),
>  		ipmr_forward_finish);
>  	return;
>  
> diff --git a/net/ipv4/route.c b/net/ipv4/route.c
> index 4dce0de6ab89..0f31ae4da3d9 100644
> --- a/net/ipv4/route.c
> +++ b/net/ipv4/route.c
> @@ -413,11 +413,11 @@ static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst,
>  					   const void *daddr)
>  {
>  	const struct rtable *rt = container_of(dst, struct rtable, dst);
> -	struct net_device *dev = dst_dev(dst);
> +	struct net_device *dev;
>  	struct neighbour *n;
>  
>  	rcu_read_lock();
> -
> +	dev = dst_dev_rcu(dst);
>  	if (likely(rt->rt_gw_family == AF_INET)) {
>  		n = ip_neigh_gw4(dev, rt->rt_gw4);
>  	} else if (rt->rt_gw_family == AF_INET6) {
> 
> ---
> base-commit: 7155f3c7a69b8480e785f2a4252d31df95daa8d1
> change-id: 20260820-cve-2025-40074-b2b8c05342a1
> 
> Best regards,
> --  
> Miguel Gazquez (Schneider Electric) <miguel.gazquez@bootlin.com>
> 
> 

Doesn't apply to the queue anymore due to me taking this patch series
from Sasha:
	https://lore.kernel.org/r/20260821144926.3428433-1-sashal@kernel.org

Can you rebase it on that?

thanks,

greg k-h

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

* Re: [PATCH 6.12.y v2] ipv4: start using dst_dev_rcu()
  2026-08-24  9:05 ` Greg KH
@ 2026-08-25 11:49   ` Sasha Levin
  0 siblings, 0 replies; 3+ messages in thread
From: Sasha Levin @ 2026-08-25 11:49 UTC (permalink / raw)
  To: Miguel Gazquez (Schneider Electric)
  Cc: Sasha Levin, stable, Eric Dumazet, David S. Miller, David Ahern,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Martin KaFai Lau,
	Wei Wang, thomas.petazzoni, netdev, linux-kernel, Greg KH

On Mon, Aug 24, 2026 at 11:05:52AM +0200, Greg KH wrote:
> Doesn't apply to the queue anymore due to me taking this patch series
> from Sasha:
> 	https://lore.kernel.org/r/20260821144926.3428433-1-sashal@kernel.org
>
> Can you rebase it on that?

Miguel, no need to respin - I've already redone the backport on top of
that series. Queued for 6.12, thanks.

-- 
Thanks,
Sasha

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

end of thread, other threads:[~2026-08-25 11:49 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-21  9:54 [PATCH 6.12.y v2] ipv4: start using dst_dev_rcu() Miguel Gazquez (Schneider Electric)
2026-08-24  9:05 ` Greg KH
2026-08-25 11:49   ` Sasha Levin

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