Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipv4: start using dst_dev_rcu()

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().

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>

authored by

Eric Dumazet and committed by
Jakub Kicinski
6ad8de3c b62a59c1

+12 -10
+3 -3
net/ipv4/icmp.c
··· 319 319 return true; 320 320 321 321 /* No rate limit on loopback */ 322 - dev = dst_dev(dst); 322 + rcu_read_lock(); 323 + dev = dst_dev_rcu(dst); 323 324 if (dev && (dev->flags & IFF_LOOPBACK)) 324 325 goto out; 325 326 326 - rcu_read_lock(); 327 327 peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, 328 328 l3mdev_master_ifindex_rcu(dev)); 329 329 rc = inet_peer_xrlim_allow(peer, 330 330 READ_ONCE(net->ipv4.sysctl_icmp_ratelimit)); 331 - rcu_read_unlock(); 332 331 out: 332 + rcu_read_unlock(); 333 333 if (!rc) 334 334 __ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST); 335 335 else
+4 -2
net/ipv4/ip_fragment.c
··· 476 476 /* Process an incoming IP datagram fragment. */ 477 477 int ip_defrag(struct net *net, struct sk_buff *skb, u32 user) 478 478 { 479 - struct net_device *dev = skb->dev ? : skb_dst_dev(skb); 480 - int vif = l3mdev_master_ifindex_rcu(dev); 479 + struct net_device *dev; 481 480 struct ipq *qp; 481 + int vif; 482 482 483 483 __IP_INC_STATS(net, IPSTATS_MIB_REASMREQDS); 484 484 485 485 /* Lookup (or create) queue header */ 486 486 rcu_read_lock(); 487 + dev = skb->dev ? : skb_dst_dev_rcu(skb); 488 + vif = l3mdev_master_ifindex_rcu(dev); 487 489 qp = ip_find(net, ip_hdr(skb), user, vif); 488 490 if (qp) { 489 491 int ret, refs = 0;
+3 -3
net/ipv4/ipmr.c
··· 1905 1905 return -1; 1906 1906 } 1907 1907 1908 - encap += LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len; 1908 + encap += LL_RESERVED_SPACE(dst_dev_rcu(&rt->dst)) + rt->dst.header_len; 1909 1909 1910 1910 if (skb_cow(skb, encap)) { 1911 1911 ip_rt_put(rt); ··· 1958 1958 * result in receiving multiple packets. 1959 1959 */ 1960 1960 NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, 1961 - net, NULL, skb, skb->dev, rt->dst.dev, 1961 + net, NULL, skb, skb->dev, dst_dev_rcu(&rt->dst), 1962 1962 ipmr_forward_finish); 1963 1963 return; 1964 1964 ··· 2302 2302 2303 2303 guard(rcu)(); 2304 2304 2305 - dev = rt->dst.dev; 2305 + dev = dst_dev_rcu(&rt->dst); 2306 2306 2307 2307 if (IPCB(skb)->flags & IPSKB_FORWARDED) 2308 2308 goto mc_output;
+2 -2
net/ipv4/route.c
··· 414 414 const void *daddr) 415 415 { 416 416 const struct rtable *rt = container_of(dst, struct rtable, dst); 417 - struct net_device *dev = dst_dev(dst); 417 + struct net_device *dev; 418 418 struct neighbour *n; 419 419 420 420 rcu_read_lock(); 421 - 421 + dev = dst_dev_rcu(dst); 422 422 if (likely(rt->rt_gw_family == AF_INET)) { 423 423 n = ip_neigh_gw4(dev, rt->rt_gw4); 424 424 } else if (rt->rt_gw_family == AF_INET6) {