Re: [PATCH mptcp-net v3] mptcp: pm: fix data race in add_addr timer callback

Matthieu Baerts <[email protected]> Wed, 22 Jul 2026 11:47:28 +0200
Newsgroups dev.linux.lists.mptcp
Organization NGI0 Core
Message-ID <[email protected]>
Hi Qing,

Thank you for the new version.

On 22/07/2026 11:13, luoqing wrote:
> From: Qing Luo <[email protected]>
> 
> The timer callback reads entry->retrans_times outside pm.lock to decide
> whether to call mptcp_pm_subflow_established(). Since
> mptcp_pm_announced_del_timer() can concurrently set retrans_times =
> ADD_ADDR_RETRANS_MAX under pm.lock, a race condition exists.

Don't forget to reply to each question from previous reviews ;)

How did you find the bug? Do you have a reproducer or is it by analysing
the code?

Were you assisted by a tool/LLM? If yes, please add the Assisted-by tag.

> Use a local 'completed' flag set inside pm.lock when retrans_times
> reaches ADD_ADDR_RETRANS_MAX. This ensures that
> mptcp_pm_subflow_established() is only called when the retransmission
> naturally exhausts.
> 
> Fixes: 348d5c1dec60 ("mptcp: move to next addr when timeout")
> Signed-off-by: Qing Luo <[email protected]>
> ---
>  net/mptcp/pm.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
> index 6afd39aea110..f93fefbb727e 100644
> --- a/net/mptcp/pm.c
> +++ b/net/mptcp/pm.c
> @@ -380,6 +380,7 @@ static void mptcp_pm_add_addr_timer(struct timer_list *timer)
>  	struct mptcp_sock *msk = entry->sock;
>  	struct sock *sk = (struct sock *)msk;
>  	unsigned int timeout = 0;
> +	bool completed = false;
>  
>  	pr_debug("msk=%p\n", msk);
>  
> @@ -414,12 +415,14 @@ static void mptcp_pm_add_addr_timer(struct timer_list *timer)
>  
>  	if (entry->retrans_times < ADD_ADDR_RETRANS_MAX)
>  		timeout <<= entry->retrans_times;
> -	else
> +	else {
>  		timeout = 0;
> +		completed = true;
> +	}

Here, you still have the checkpatch warning Gang reported:

  CHECK: braces {} should be used on all arms of this statement

To avoid all these modifications, I think it would be better to have:

  bool completed;

  (...)

  completed = entry->retrans_times >= ADD_ADDR_RETRANS_MAX;
  if (!completed)
      timeout <<= entry->retrans_times;
  else
      timeout = 0;

Or maybe better with the opposite:

  bool retransmit;

  (...)

  retransmit = entry->retrans_times < ADD_ADDR_RETRANS_MAX;
  if (retransmit)
      timeout <<= entry->retrans_times;
  else
      timeout = 0;

  (...)

  if (!retransmit)
     mptcp_pm_subflow_established(msk);

By doing that, you only need to modify the if conditions, not the "else"
parts.

>  
>  	spin_unlock_bh(&msk->pm.lock);
>  
> -	if (entry->retrans_times == ADD_ADDR_RETRANS_MAX)
> +	if (completed)
>  		mptcp_pm_subflow_established(msk);
>  
>  out:

Cheers,
Matt
-- 
Sponsored by the NGI0 Core fund.