]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: use dst_dev_rcu() in sk_setup_caps()
authorEric Dumazet <edumazet@google.com>
Fri, 2 Jan 2026 20:37:26 +0000 (12:37 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 8 Jan 2026 09:15:01 +0000 (10:15 +0100)
[ Upstream commit 99a2ace61b211b0be861b07fbaa062fca4b58879 ]

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>
[Harshit: Backport to 6.12.y, resolve conflict due to missing commit:
22d6c9eebf2e ("net: Unexport shared functions for DCCP.")  in 6.12.y]
Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
include/net/ip.h
include/net/ip6_route.h
include/net/route.h
net/core/sock.c

index 5f0f1215d2f923bd02f16208edef04c5dddd2abd..c65ca2765e29a2e7b44882593afcf04a72c9b036 100644 (file)
@@ -470,12 +470,14 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
                                                    bool forwarding)
 {
        const struct rtable *rt = dst_rtable(dst);
+       const struct net_device *dev;
        unsigned int mtu, res;
        struct net *net;
 
        rcu_read_lock();
 
-       net = dev_net_rcu(dst_dev(dst));
+       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) {
@@ -489,7 +491,7 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
        if (mtu)
                goto out;
 
-       mtu = READ_ONCE(dst_dev(dst)->mtu);
+       mtu = READ_ONCE(dev->mtu);
 
        if (unlikely(ip_mtu_locked(dst))) {
                if (rt->rt_uses_gateway && mtu > 576)
index 9255f21818ee7b03d2608fd399b082c0098c7028..59f48ca3abdf5a8aef6b4ece13f9a1774fc04f38 100644 (file)
@@ -337,7 +337,7 @@ static inline unsigned int ip6_dst_mtu_maybe_forward(const struct dst_entry *dst
 
        mtu = IPV6_MIN_MTU;
        rcu_read_lock();
-       idev = __in6_dev_get(dst_dev(dst));
+       idev = __in6_dev_get(dst_dev_rcu(dst));
        if (idev)
                mtu = READ_ONCE(idev->cnf.mtu6);
        rcu_read_unlock();
index 232b7bf55ba2219abbac60165c230e1e67573b4e..cbb4d55230627c85befa48ff61efb6c679a42c38 100644 (file)
@@ -369,7 +369,7 @@ static inline int ip4_dst_hoplimit(const struct dst_entry *dst)
                const struct net *net;
 
                rcu_read_lock();
-               net = dev_net_rcu(dst_dev(dst));
+               net = dst_dev_net_rcu(dst);
                hoplimit = READ_ONCE(net->ipv4.sysctl_ip_default_ttl);
                rcu_read_unlock();
        }
index 1781f3a642b46fe354aeab09fa55024c88769aef..97cc796a1d334553198a2f7128d4bb4a565640c0 100644 (file)
@@ -2524,7 +2524,7 @@ void sk_free_unlock_clone(struct sock *sk)
 }
 EXPORT_SYMBOL_GPL(sk_free_unlock_clone);
 
-static u32 sk_dst_gso_max_size(struct sock *sk, struct dst_entry *dst)
+static u32 sk_dst_gso_max_size(struct sock *sk, const struct net_device *dev)
 {
        bool is_ipv6 = false;
        u32 max_size;
@@ -2534,8 +2534,8 @@ static u32 sk_dst_gso_max_size(struct sock *sk, struct dst_entry *dst)
                   !ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr));
 #endif
        /* pairs with the WRITE_ONCE() in netif_set_gso(_ipv4)_max_size() */
-       max_size = is_ipv6 ? READ_ONCE(dst_dev(dst)->gso_max_size) :
-                       READ_ONCE(dst_dev(dst)->gso_ipv4_max_size);
+       max_size = is_ipv6 ? READ_ONCE(dev->gso_max_size) :
+                       READ_ONCE(dev->gso_ipv4_max_size);
        if (max_size > GSO_LEGACY_MAX_SIZE && !sk_is_tcp(sk))
                max_size = GSO_LEGACY_MAX_SIZE;
 
@@ -2544,9 +2544,12 @@ static u32 sk_dst_gso_max_size(struct sock *sk, struct dst_entry *dst)
 
 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;
+       rcu_read_lock();
+       dev = dst_dev_rcu(dst);
+       sk->sk_route_caps = dev->features;
        if (sk_is_tcp(sk)) {
                struct inet_connection_sock *icsk = inet_csk(sk);
 
@@ -2562,13 +2565,14 @@ 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 = sk_dst_gso_max_size(sk, dst);
+                       sk->sk_gso_max_size = sk_dst_gso_max_size(sk, dev);
                        /* pairs with the WRITE_ONCE() in netif_set_gso_max_segs() */
-                       max_segs = max_t(u32, READ_ONCE(dst_dev(dst)->gso_max_segs), 1);
+                       max_segs = max_t(u32, READ_ONCE(dev->gso_max_segs), 1);
                }
        }
        sk->sk_gso_max_segs = max_segs;
        sk_dst_set(sk, dst);
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(sk_setup_caps);