Commit 70238e58 authored by Eric Dumazet's avatar Eric Dumazet Committed by Wentao Guan
Browse files

ndisc: extend RCU protection in ndisc_send_skb()

stable inclusion
from stable-v6.6.79
commit ae38982f521621c216fc2f5182cd091f4734641d
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IBXANC

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=ae38982f521621c216fc2f5182cd091f4734641d



--------------------------------

[ Upstream commit ed6ae1f325d3c43966ec1b62ac1459e2b8e45640 ]

ndisc_send_skb() can be called without RTNL or RCU held.

Acquire rcu_read_lock() earlier, so that we can use dev_net_rcu()
and avoid a potential UAF.

Fixes: 1762f7e8 ("[NETNS][IPV6] ndisc - make socket control per namespace")
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarDavid Ahern <dsahern@kernel.org>
Reviewed-by: default avatarKuniyuki Iwashima <kuniyu@amazon.com>
Link: https://patch.msgid.link/20250207135841.1948589-8-edumazet@google.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
(cherry picked from commit ae38982f521621c216fc2f5182cd091f4734641d)
Signed-off-by: default avatarWentao Guan <guanwentao@uniontech.com>
parent cbb9c721
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -471,16 +471,20 @@ static void ip6_nd_hdr(struct sk_buff *skb,
void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
		    const struct in6_addr *saddr)
{
	struct icmp6hdr *icmp6h = icmp6_hdr(skb);
	struct dst_entry *dst = skb_dst(skb);
	struct net *net = dev_net(skb->dev);
	struct sock *sk = net->ipv6.ndisc_sk;
	struct inet6_dev *idev;
	struct net *net;
	struct sock *sk;
	int err;
	struct icmp6hdr *icmp6h = icmp6_hdr(skb);
	u8 type;

	type = icmp6h->icmp6_type;

	rcu_read_lock();

	net = dev_net_rcu(skb->dev);
	sk = net->ipv6.ndisc_sk;
	if (!dst) {
		struct flowi6 fl6;
		int oif = skb->dev->ifindex;
@@ -488,6 +492,7 @@ void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
		icmpv6_flow_init(sk, &fl6, type, saddr, daddr, oif);
		dst = icmp6_dst_alloc(skb->dev, &fl6);
		if (IS_ERR(dst)) {
			rcu_read_unlock();
			kfree_skb(skb);
			return;
		}
@@ -502,7 +507,6 @@ void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,

	ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len);

	rcu_read_lock();
	idev = __in6_dev_get(dst->dev);
	IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTREQUESTS);