mirror of
https://github.com/torvalds/linux.git
synced 2026-09-11 20:13:02 +02:00
ipv6: mcast: fix RCU list diversion in ip6_mc_del1_src()
When removing a source filter whose count reaches zero, ip6_mc_del1_src()
unlinks psf from pmc->mca_sources. If the filter was previously active,
the code moved psf directly into pmc->mca_tomb by updating psf->sf_next.
Because pmc->mca_sources is traversed locklessly under RCU (e.g. by
ipv6_chk_mcast_addr()), mutating psf->sf_next before a grace period
elapses diverts concurrent readers to the tombstone list. Consequently,
readers miss remaining active sources in pmc->mca_sources and improperly
examine deleted tombstone entries.
Fix this by allocating a new tombstone node for pmc->mca_tomb (as done
in sf_setstate()) and retiring the original psf via kfree_rcu().
Fixes: 4b200e3989 ("mld: convert ip6_sf_list to RCU")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Taehee Yoo <ap420073@gmail.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260828084531.1826790-2-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
d8d4d1cf40
commit
93b4923984
|
|
@ -2351,14 +2351,18 @@ static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
|
|||
|
||||
if (psf->sf_oldin && !(pmc->mca_flags & MAF_NOREPORT) &&
|
||||
!mld_in_v1_mode(idev)) {
|
||||
psf->sf_crcount = idev->mc_qrv;
|
||||
rcu_assign_pointer(psf->sf_next,
|
||||
mc_dereference(pmc->mca_tomb, idev));
|
||||
rcu_assign_pointer(pmc->mca_tomb, psf);
|
||||
rv = 1;
|
||||
} else {
|
||||
kfree_rcu(psf, rcu);
|
||||
struct ip6_sf_list *dpsf = kmalloc_obj(*dpsf);
|
||||
|
||||
if (dpsf) {
|
||||
*dpsf = *psf;
|
||||
dpsf->sf_crcount = idev->mc_qrv;
|
||||
rcu_assign_pointer(dpsf->sf_next,
|
||||
mc_dereference(pmc->mca_tomb, idev));
|
||||
rcu_assign_pointer(pmc->mca_tomb, dpsf);
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
kfree_rcu(psf, rcu);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user