When joining a multicast group, if a report timer is already running (e.g. scheduled by a query or a previous join), igmp6_join_group() cancels the delayed work and recalculates the delay: if (cancel_delayed_work(&ma->mca_work)) { refcount_dec(&ma->mca_refcnt); delay = ma->mca_work.timer.expires - jiffies; } Unlike igmp6_group_queried(), igmp6_join_group() did not check if delay >= interval. This leads to two issues: 1. If the timer has already expired (timer.expires <= jiffies), ma->mca_work.timer.expires - jiffies underflows to a very large unsigned long value (~ULONG_MAX), causing mod_delayed_work() to schedule the report weeks/months into the future. 2. If the timer was armed by a query with a large maximum response delay, delay could exceed unsolicited_report_interval(ma->idev). Fix this by initializing delay to unsolicited_report_interval(ma->idev) and clamping delay with get_random_u32_below(interval) when delay >= interval, mirroring the logic in igmp6_group_queried(). Fixes: 2d9a93b4902b ("mld: convert from timer to delayed work") Signed-off-by: Eric Dumazet Cc: Taehee Yoo --- net/ipv6/mcast.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 40e996f36c37325adee9165ce9842559da039c04..44fdde940dcdcd16a7642b2be60c6866c574ce92 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2640,7 +2640,7 @@ static void ip6_mc_clear_src(struct ifmcaddr6 *pmc) static void igmp6_join_group(struct ifmcaddr6 *ma) { - unsigned long delay; + unsigned long delay, interval; mc_assert_locked(ma->idev); @@ -2649,13 +2649,17 @@ static void igmp6_join_group(struct ifmcaddr6 *ma) igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT); - delay = get_random_u32_below(unsolicited_report_interval(ma->idev)); + interval = unsolicited_report_interval(ma->idev); + delay = interval; if (cancel_delayed_work(&ma->mca_work)) { refcount_dec(&ma->mca_refcnt); delay = ma->mca_work.timer.expires - jiffies; } + if (delay >= interval) + delay = get_random_u32_below(interval); + if (!mod_delayed_work(mld_wq, &ma->mca_work, delay)) refcount_inc(&ma->mca_refcnt); WRITE_ONCE(ma->mca_flags, ma->mca_flags | -- 2.55.0.860.g4b6b3295ed-goog