Skip to content

Commit c97802d

Browse files
CKI Backport BotHangbin Liu
authored andcommitted
ipv6: mcast: Don't hold RTNL for IPV6_ADD_MEMBERSHIP and MCAST_JOIN_GROUP.
JIRA: https://issues.redhat.com/browse/RHEL-115325 commit 1767bb2 Author: Kuniyuki Iwashima <kuniyu@google.com> Date: Wed Jul 2 16:01:23 2025 -0700 ipv6: mcast: Don't hold RTNL for IPV6_ADD_MEMBERSHIP and MCAST_JOIN_GROUP. In __ipv6_sock_mc_join(), per-socket mld data is protected by lock_sock(), and only __dev_get_by_index() requires RTNL. Let's use dev_get_by_index() and drop RTNL for IPV6_ADD_MEMBERSHIP and MCAST_JOIN_GROUP. Note that we must call rt6_lookup() and dev_hold() under RCU. If rt6_lookup() returns an entry from the exception table, dst_dev_put() could change rt->dev.dst to loopback concurrently, and the original device could lose the refcount before dev_hold() and unblock device registration. dst_dev_put() is called from NETDEV_UNREGISTER and synchronize_net() follows it, so as long as rt6_lookup() and dev_hold() are called within the same RCU critical section, the dev is alive. Even if the race happens, they are synchronised by idev->dead and mcast addresses are cleaned up. For the racy access to rt->dst.dev, we use dst_dev(). Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20250702230210.3115355-7-kuni1840@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
1 parent f0b784b commit c97802d

File tree

2 files changed

+13
-13
lines changed

2 files changed

+13
-13
lines changed

net/ipv6/ipv6_sockglue.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,9 @@ static bool setsockopt_needs_rtnl(int optname)
121121
{
122122
switch (optname) {
123123
case IPV6_ADDRFORM:
124-
case IPV6_ADD_MEMBERSHIP:
125124
case IPV6_DROP_MEMBERSHIP:
126125
case IPV6_JOIN_ANYCAST:
127126
case IPV6_LEAVE_ANYCAST:
128-
case MCAST_JOIN_GROUP:
129127
case MCAST_LEAVE_GROUP:
130128
case MCAST_JOIN_SOURCE_GROUP:
131129
case MCAST_LEAVE_SOURCE_GROUP:

net/ipv6/mcast.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,12 @@ static int unsolicited_report_interval(struct inet6_dev *idev)
175175
static int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
176176
const struct in6_addr *addr, unsigned int mode)
177177
{
178-
struct net_device *dev = NULL;
179-
struct ipv6_mc_socklist *mc_lst;
180178
struct ipv6_pinfo *np = inet6_sk(sk);
179+
struct ipv6_mc_socklist *mc_lst;
181180
struct net *net = sock_net(sk);
181+
struct net_device *dev = NULL;
182182
int err;
183183

184-
ASSERT_RTNL();
185-
186184
if (!ipv6_addr_is_multicast(addr))
187185
return -EINVAL;
188186

@@ -202,13 +200,18 @@ static int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
202200

203201
if (ifindex == 0) {
204202
struct rt6_info *rt;
203+
204+
rcu_read_lock();
205205
rt = rt6_lookup(net, addr, NULL, 0, NULL, 0);
206206
if (rt) {
207-
dev = rt->dst.dev;
207+
dev = dst_dev(&rt->dst);
208+
dev_hold(dev);
208209
ip6_rt_put(rt);
209210
}
210-
} else
211-
dev = __dev_get_by_index(net, ifindex);
211+
rcu_read_unlock();
212+
} else {
213+
dev = dev_get_by_index(net, ifindex);
214+
}
212215

213216
if (!dev) {
214217
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
@@ -219,12 +222,11 @@ static int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
219222
mc_lst->sfmode = mode;
220223
RCU_INIT_POINTER(mc_lst->sflist, NULL);
221224

222-
/*
223-
* now add/increase the group membership on the device
224-
*/
225-
225+
/* now add/increase the group membership on the device */
226226
err = __ipv6_dev_mc_inc(dev, addr, mode);
227227

228+
dev_put(dev);
229+
228230
if (err) {
229231
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
230232
return err;

0 commit comments

Comments
 (0)