From: Eric Dumazet <edumazet@google.com> mainline inclusion from mainline-v6.18-rc1 commit 99a2ace61b211b0be861b07fbaa062fca4b58879 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/ID3WJ1 CVE: CVE-2025-40074 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- Use RCU to protect accesses to dst->dev from sk_setup_caps() and sk_dst_gso_max_size(). Also use dst_dev_rcu() in ip6_dst_mtu_maybe_forward(), and ip_dst_mtu_maybe_forward(). ip4_dst_hoplimit() can use dst_dev_net_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-6-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Conflicts: include/net/ip.h include/net/ip6_route.h include/net/route.h net/core/sock.c [commit 1caf27297215 and ac6627a28dbf(ip.h) 469308552ca4(route.h), b1a78b9b9886 and d0d598ca86bd(sock.c) are not backport] Signed-off-by: Dong Chenchen <dongchenchen2@huawei.com> --- include/net/ip.h | 6 ++++-- include/net/ip6_route.h | 2 +- include/net/route.h | 9 +++++++-- net/core/sock.c | 10 +++++++--- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index 6ecea4ef54dc..72415f77934a 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -442,12 +442,14 @@ static inline bool ip_sk_ignore_df(const struct sock *sk) static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst, bool forwarding) { + const struct net_device *dev; unsigned int mtu, res; struct net *net; rcu_read_lock(); - net = dev_net_rcu(dst->dev); + dev = dst_dev_rcu(dst); + net = dev_net_rcu(dev); if (READ_ONCE(net->ipv4.sysctl_ip_fwd_use_pmtu) || ip_mtu_locked(dst) || !forwarding) { @@ -458,7 +460,7 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst, /* 'forwarding = true' case should always honour route mtu */ mtu = dst_metric_raw(dst, RTAX_MTU); if (!mtu) - mtu = min(READ_ONCE(dst->dev->mtu), IP_MAX_MTU); + mtu = min(READ_ONCE(dev->mtu), IP_MAX_MTU); res = mtu - lwtunnel_headroom(dst->lwtstate, mtu); out: diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 44969d03debf..69ef838f91d6 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -328,7 +328,7 @@ static inline unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst) mtu = IPV6_MIN_MTU; rcu_read_lock(); - idev = __in6_dev_get(dst->dev); + idev = __in6_dev_get(dst_dev_rcu(dst)); if (idev) mtu = idev->cnf.mtu6; rcu_read_unlock(); diff --git a/include/net/route.h b/include/net/route.h index 2551f3f03b37..07d6fa94a6a8 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -357,10 +357,15 @@ static inline int inet_iif(const struct sk_buff *skb) static inline int ip4_dst_hoplimit(const struct dst_entry *dst) { int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT); - struct net *net = dev_net(dst->dev); - if (hoplimit == 0) + if (hoplimit == 0) { + const struct net *net; + + rcu_read_lock(); + net = dst_dev_net_rcu(dst); hoplimit = net->ipv4.sysctl_ip_default_ttl; + rcu_read_unlock(); + } return hoplimit; } diff --git a/net/core/sock.c b/net/core/sock.c index 6d1d465511ad..b22ff2f641ab 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2053,9 +2053,12 @@ EXPORT_SYMBOL_GPL(sk_free_unlock_clone); void sk_setup_caps(struct sock *sk, struct dst_entry *dst) { + const struct net_device *dev; u32 max_segs = 1; - sk->sk_route_caps = dst_dev(dst)->features | sk->sk_route_forced_caps; + rcu_read_lock(); + dev = dst_dev_rcu(dst); + sk->sk_route_caps = dev->features | sk->sk_route_forced_caps; if (sk->sk_route_caps & NETIF_F_GSO) sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE; sk->sk_route_caps &= ~sk->sk_route_nocaps; @@ -2064,14 +2067,15 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst) sk->sk_route_caps &= ~NETIF_F_GSO_MASK; } else { sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; - sk->sk_gso_max_size = dst_dev(dst)->gso_max_size; - max_segs = max_t(u32, dst_dev(dst)->gso_max_segs, 1); + sk->sk_gso_max_size = dev->gso_max_size; + max_segs = max_t(u32, dev->gso_max_segs, 1); } } sk->sk_gso_max_segs = max_segs; sk_dst_set(sk, dst); net_rship_sk_dst_set(sk, dst); + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(sk_setup_caps); -- 2.25.1