diff options
| author | Eric Dumazet <edumazet@google.com> | 2025-02-07 13:58:39 +0000 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2025-02-21 13:50:08 +0100 |
| commit | a9319d800b5701e7f5e3fa71a5b7c4831fc20d6d (patch) | |
| tree | 0211bf9c9bfa00452462f4304f0b004ff1c288d5 /net | |
| parent | 7e01abc34e87abd091e619161a20f54ed4e3e2da (diff) | |
| download | linux-a9319d800b5701e7f5e3fa71a5b7c4831fc20d6d.tar.gz linux-a9319d800b5701e7f5e3fa71a5b7c4831fc20d6d.tar.bz2 linux-a9319d800b5701e7f5e3fa71a5b7c4831fc20d6d.zip | |
ndisc: extend RCU protection in ndisc_send_skb()
[ 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: 1762f7e88eb3 ("[NETNS][IPV6] ndisc - make socket control per namespace")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://patch.msgid.link/20250207135841.1948589-8-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'net')
| -rw-r--r-- | net/ipv6/ndisc.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 2e8e0847631e..1a6408a24d21 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -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_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); |
