mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
ipv4: igmp: Fix potential memory leaks in igmp_mod_timer() and igmp_stop_timer()
When a timer is deleted and not re-armed in igmp_mod_timer(), or stopped
in igmp_stop_timer(), the code currently decrements the reference counter
of the multicast list entry @im using refcount_dec(&im->refcnt).
However, both functions can be called from the RCU reader path:
- igmp_mod_timer() via igmp_heard_query() -> for_each_pmc_rcu()
- igmp_stop_timer() via igmp_rcv() -> igmp_heard_report()
If the group im was concurrently removed from the list by ip_mc_dec_group(),
its reference count might have already been decremented to 1.
In this case, timer_delete() succeeds, and refcount_dec() decrements
the refcount from 1 to 0. Since refcount_dec() does not free the object
when it hits 0 (unlike ip_ma_put()), the im structure is leaked.
Fix this by using ip_ma_put(im) instead of refcount_dec(&im->refcnt),
and deferring the put until after the spinlock is released.
Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20260705181756.963063-4-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
9b26518b68
commit
3546deaa0c
|
|
@ -217,13 +217,18 @@ static void ip_sf_list_clear_all(struct ip_sf_list *psf)
|
|||
|
||||
static void igmp_stop_timer(struct ip_mc_list *im)
|
||||
{
|
||||
bool put = false;
|
||||
|
||||
spin_lock_bh(&im->lock);
|
||||
if (timer_delete(&im->timer))
|
||||
refcount_dec(&im->refcnt);
|
||||
put = true;
|
||||
WRITE_ONCE(im->tm_running, 0);
|
||||
WRITE_ONCE(im->reporter, 0);
|
||||
im->unsolicit_count = 0;
|
||||
spin_unlock_bh(&im->lock);
|
||||
|
||||
if (put)
|
||||
ip_ma_put(im);
|
||||
}
|
||||
|
||||
/* It must be called with locked im->lock */
|
||||
|
|
@ -266,6 +271,8 @@ static void igmp_ifc_start_timer(struct in_device *in_dev, int delay)
|
|||
|
||||
static void igmp_mod_timer(struct ip_mc_list *im, int max_delay)
|
||||
{
|
||||
bool put = false;
|
||||
|
||||
spin_lock_bh(&im->lock);
|
||||
im->unsolicit_count = 0;
|
||||
if (timer_delete(&im->timer)) {
|
||||
|
|
@ -275,10 +282,13 @@ static void igmp_mod_timer(struct ip_mc_list *im, int max_delay)
|
|||
spin_unlock_bh(&im->lock);
|
||||
return;
|
||||
}
|
||||
refcount_dec(&im->refcnt);
|
||||
put = true;
|
||||
}
|
||||
igmp_start_timer(im, max_delay);
|
||||
spin_unlock_bh(&im->lock);
|
||||
|
||||
if (put)
|
||||
ip_ma_put(im);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user