CVE-2026-46137
Description
In the Linux kernel, the following vulnerability has been resolved:
mptcp: pm: ADD_ADDR rtx: fix potential data-race
This mptcp_pm_add_timer() helper is executed as a timer callback in softirq context. To avoid any data races, the socket lock needs to be held with bh_lock_sock().
If the socket is in use, retry again soon after, similar to what is done with the keepalive timer.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A data-race in Linux kernel MPTCP's ADD_ADDR retransmission timer can occur when the socket lock is not held, potentially causing concurrency issues.
Vulnerability
The MPTCP path manager's ADD_ADDR retransmission timer, implemented in mptcp_pm_add_timer(), is executed as a timer callback in softirq context. The code failed to hold the socket lock via bh_lock_sock(), leading to a potential data-race when the socket is accessed concurrently. This affects Linux kernel versions containing the MPTCP subsystem prior to the fix introduced in commit 5cd6e0ad79d2615264f63929f8b457ad97ae550d [1].
Exploitation
An attacker would need to trigger the MPTCP ADD_ADDR retransmission timer while the socket is in use by another context (e.g., user space or other kernel paths). No authentication or special privileges are mentioned; the race occurs during normal MPTCP operation. The exact sequence of steps is not specified in the available references.
Impact
A data-race can lead to undefined behavior, including memory corruption, use-after-free, or other concurrency bugs. The impact may vary depending on the kernel configuration and workload, but it could result in system instability or information disclosure.
Mitigation
The fix is included in the Linux kernel stable commit 5cd6e0ad79d2615264f63929f8b457ad97ae550d [1]. Users should update to a kernel version containing this patch. No workaround is documented.
AI Insight generated on May 28, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
1Patches
10013dcdc19615mptcp: pm: ADD_ADDR rtx: fix potential data-race
1 file changed · +8 −1
net/mptcp/pm_netlink.c+8 −1 modifieddiff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index a2f15d332da597..440dfc4d362419 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -308,6 +308,13 @@ static void mptcp_pm_add_timer(struct timer_list *timer) if (!entry->addr.id) return; + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* Try again later. */ + sk_reset_timer(sk, timer, jiffies + HZ / 20); + goto out; + } + if (mptcp_pm_should_add_signal_addr(msk)) { sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); goto out; @@ -336,6 +343,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer) mptcp_pm_subflow_established(msk); out: + bh_unlock_sock(sk); __sock_put(sk); } -- cgit 1.3-korg
6e4710d7d878mptcp: pm: ADD_ADDR rtx: fix potential data-race
1 file changed · +8 −1
net/mptcp/pm_netlink.c+8 −1 modifieddiff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index 11743b37d01f67..b17eaea26ce4b1 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -307,6 +307,13 @@ static void mptcp_pm_add_timer(struct timer_list *timer) if (!entry->addr.id) return; + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* Try again later. */ + sk_reset_timer(sk, timer, jiffies + HZ / 20); + goto out; + } + if (mptcp_pm_should_add_signal_addr(msk)) { sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); goto out; @@ -335,6 +342,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer) mptcp_pm_subflow_established(msk); out: + bh_unlock_sock(sk); __sock_put(sk); } -- cgit 1.3-korg
2ad56e434199mptcp: pm: ADD_ADDR rtx: fix potential data-race
1 file changed · +8 −1
net/mptcp/pm.c+8 −1 modifieddiff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 8852aef5e61879..5cb62ab42cbe1f 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -350,6 +350,13 @@ static void mptcp_pm_add_timer(struct timer_list *timer) if (inet_sk_state_load(sk) == TCP_CLOSE) return; + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* Try again later. */ + sk_reset_timer(sk, timer, jiffies + HZ / 20); + goto out; + } + if (mptcp_pm_should_add_signal_addr(msk)) { sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); goto out; @@ -378,6 +385,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer) mptcp_pm_subflow_established(msk); out: + bh_unlock_sock(sk); __sock_put(sk); } -- cgit 1.3-korg
5cd6e0ad79d2mptcp: pm: ADD_ADDR rtx: fix potential data-race
1 file changed · +8 −1
net/mptcp/pm.c+8 −1 modifieddiff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 5056eb8db24e05..3912128d9b8668 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -337,6 +337,13 @@ static void mptcp_pm_add_timer(struct timer_list *timer) if (inet_sk_state_load(sk) == TCP_CLOSE) return; + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* Try again later. */ + sk_reset_timer(sk, timer, jiffies + HZ / 20); + goto out; + } + if (mptcp_pm_should_add_signal_addr(msk)) { sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); goto out; @@ -365,6 +372,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer) mptcp_pm_subflow_established(msk); out: + bh_unlock_sock(sk); __sock_put(sk); } -- cgit 1.3-korg
cc3c0399361emptcp: pm: ADD_ADDR rtx: fix potential data-race
1 file changed · +8 −1
net/mptcp/pm.c+8 −1 modifieddiff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index c46b7b0ca71380..24295517711b46 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -350,6 +350,13 @@ static void mptcp_pm_add_timer(struct timer_list *timer) if (inet_sk_state_load(sk) == TCP_CLOSE) return; + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* Try again later. */ + sk_reset_timer(sk, timer, jiffies + HZ / 20); + goto out; + } + if (mptcp_pm_should_add_signal_addr(msk)) { sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); goto out; @@ -378,6 +385,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer) mptcp_pm_subflow_established(msk); out: + bh_unlock_sock(sk); __sock_put(sk); } -- cgit 1.3-korg
013dcdc19615mptcp: pm: ADD_ADDR rtx: fix potential data-race
1 file changed · +8 −1
net/mptcp/pm_netlink.c+8 −1 modifieddiff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index a2f15d332da597..440dfc4d362419 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -308,6 +308,13 @@ static void mptcp_pm_add_timer(struct timer_list *timer) if (!entry->addr.id) return; + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* Try again later. */ + sk_reset_timer(sk, timer, jiffies + HZ / 20); + goto out; + } + if (mptcp_pm_should_add_signal_addr(msk)) { sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); goto out; @@ -336,6 +343,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer) mptcp_pm_subflow_established(msk); out: + bh_unlock_sock(sk); __sock_put(sk); } -- cgit 1.3-korg
6e4710d7d878mptcp: pm: ADD_ADDR rtx: fix potential data-race
1 file changed · +8 −1
net/mptcp/pm_netlink.c+8 −1 modifieddiff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c index 11743b37d01f67..b17eaea26ce4b1 100644 --- a/net/mptcp/pm_netlink.c +++ b/net/mptcp/pm_netlink.c @@ -307,6 +307,13 @@ static void mptcp_pm_add_timer(struct timer_list *timer) if (!entry->addr.id) return; + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* Try again later. */ + sk_reset_timer(sk, timer, jiffies + HZ / 20); + goto out; + } + if (mptcp_pm_should_add_signal_addr(msk)) { sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); goto out; @@ -335,6 +342,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer) mptcp_pm_subflow_established(msk); out: + bh_unlock_sock(sk); __sock_put(sk); } -- cgit 1.3-korg
cc3c0399361emptcp: pm: ADD_ADDR rtx: fix potential data-race
1 file changed · +8 −1
net/mptcp/pm.c+8 −1 modifieddiff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index c46b7b0ca71380..24295517711b46 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -350,6 +350,13 @@ static void mptcp_pm_add_timer(struct timer_list *timer) if (inet_sk_state_load(sk) == TCP_CLOSE) return; + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* Try again later. */ + sk_reset_timer(sk, timer, jiffies + HZ / 20); + goto out; + } + if (mptcp_pm_should_add_signal_addr(msk)) { sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); goto out; @@ -378,6 +385,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer) mptcp_pm_subflow_established(msk); out: + bh_unlock_sock(sk); __sock_put(sk); } -- cgit 1.3-korg
2ad56e434199mptcp: pm: ADD_ADDR rtx: fix potential data-race
1 file changed · +8 −1
net/mptcp/pm.c+8 −1 modifieddiff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 8852aef5e61879..5cb62ab42cbe1f 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -350,6 +350,13 @@ static void mptcp_pm_add_timer(struct timer_list *timer) if (inet_sk_state_load(sk) == TCP_CLOSE) return; + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* Try again later. */ + sk_reset_timer(sk, timer, jiffies + HZ / 20); + goto out; + } + if (mptcp_pm_should_add_signal_addr(msk)) { sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); goto out; @@ -378,6 +385,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer) mptcp_pm_subflow_established(msk); out: + bh_unlock_sock(sk); __sock_put(sk); } -- cgit 1.3-korg
5cd6e0ad79d2mptcp: pm: ADD_ADDR rtx: fix potential data-race
1 file changed · +8 −1
net/mptcp/pm.c+8 −1 modifieddiff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 5056eb8db24e05..3912128d9b8668 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -337,6 +337,13 @@ static void mptcp_pm_add_timer(struct timer_list *timer) if (inet_sk_state_load(sk) == TCP_CLOSE) return; + bh_lock_sock(sk); + if (sock_owned_by_user(sk)) { + /* Try again later. */ + sk_reset_timer(sk, timer, jiffies + HZ / 20); + goto out; + } + if (mptcp_pm_should_add_signal_addr(msk)) { sk_reset_timer(sk, timer, jiffies + TCP_RTO_MAX / 8); goto out; @@ -365,6 +372,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer) mptcp_pm_subflow_established(msk); out: + bh_unlock_sock(sk); __sock_put(sk); } -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Missing socket lock acquisition in softirq timer callback allows concurrent access to shared socket state."
Attack vector
The `mptcp_pm_add_timer()` callback executes in softirq context and accesses shared socket state without holding the socket lock. A concurrent userspace operation on the same socket (e.g., a setsockopt or close) can race with the timer callback, leading to a data-race on socket fields. An attacker who can trigger ADD_ADDR retransmission timeouts while the socket is in use by userspace can exploit this race condition. The timer fires in softirq context, and without `bh_lock_sock()`, there is no synchronization against a concurrent user holding the socket lock.
Affected code
The vulnerability is in the `mptcp_pm_add_timer()` function, located in `net/mptcp/pm.c` (or `net/mptcp/pm_netlink.c` in backported versions) [patch_id=2898378]. This function is a timer callback that runs in softirq context and accesses the MPTCP socket without proper locking.
What the fix does
The patch adds `bh_lock_sock(sk)` at the start of `mptcp_pm_add_timer()` and `bh_unlock_sock(sk)` at the `out` label [patch_id=2898378]. If the socket is already owned by userspace (`sock_owned_by_user(sk)`), the timer is rescheduled for ~50ms later (`jiffies + HZ / 20`) and the callback returns early, avoiding the race. This pattern mirrors the existing keepalive timer handling in the TCP stack.
Preconditions
- configThe MPTCP connection must have an ADD_ADDR retransmission timer active (i.e., an ADD_ADDR option was sent and a timeout occurs).
- inputThe socket must be concurrently in use by a userspace thread holding the socket lock (e.g., via a setsockopt or close syscall).
Generated on May 28, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- git.kernel.org/stable/c/013dcdc1961543b9a3433466bc8c79a2f4ca75b5nvd
- git.kernel.org/stable/c/2ad56e434199ca24a812bb353667aa1c3860f513nvd
- git.kernel.org/stable/c/5cd6e0ad79d2615264f63929f8b457ad97ae550dnvd
- git.kernel.org/stable/c/6e4710d7d8782cb61af29a7e7111ddfc38b9e1a3nvd
- git.kernel.org/stable/c/cc3c0399361efaaf7ae64262eb3f70829b1189c6nvd
News mentions
0No linked articles in our index yet.