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

ndisc: use RCU protection in ndisc_alloc_skb()

stable inclusion
from stable-v6.6.79
commit 9e0ec817eb41a55327a46cd3ce331a9868d60304
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=9e0ec817eb41a55327a46cd3ce331a9868d60304



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

[ Upstream commit 628e6d18930bbd21f2d4562228afe27694f66da9 ]

ndisc_alloc_skb() can be called without RTNL or RCU being held.

Add RCU protection to avoid possible UAF.

Fixes: de09334b ("ndisc: Introduce ndisc_alloc_skb() helper.")
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-3-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 9e0ec817eb41a55327a46cd3ce331a9868d60304)
Signed-off-by: default avatarWentao Guan <guanwentao@uniontech.com>
parent ea53fdd4
Loading
Loading
Loading
Loading
+4 −6
Original line number Diff line number Diff line
@@ -418,15 +418,11 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
{
	int hlen = LL_RESERVED_SPACE(dev);
	int tlen = dev->needed_tailroom;
	struct sock *sk = dev_net(dev)->ipv6.ndisc_sk;
	struct sk_buff *skb;

	skb = alloc_skb(hlen + sizeof(struct ipv6hdr) + len + tlen, GFP_ATOMIC);
	if (!skb) {
		ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb\n",
			  __func__);
	if (!skb)
		return NULL;
	}

	skb->protocol = htons(ETH_P_IPV6);
	skb->dev = dev;
@@ -437,7 +433,9 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
	/* Manually assign socket ownership as we avoid calling
	 * sock_alloc_send_pskb() to bypass wmem buffer limits
	 */
	skb_set_owner_w(skb, sk);
	rcu_read_lock();
	skb_set_owner_w(skb, dev_net_rcu(dev)->ipv6.ndisc_sk);
	rcu_read_unlock();

	return skb;
}