FAILED: patch "[PATCH] mptcp: fix race condition in mptcp_schedule_work()" failed to apply to 5.10-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x 035bca3f017ee9dea3a5a756e77a6f7138cc6eea
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2025112402-confiding-slideshow-217f@gregkh' --subject-prefix 'PATCH 5.10.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 035bca3f017ee9dea3a5a756e77a6f7138cc6eea Mon Sep 17 00:00:00 2001
From: Eric Dumazet <[email protected]>
Date: Thu, 13 Nov 2025 10:39:24 +0000
Subject: [PATCH] mptcp: fix race condition in mptcp_schedule_work()
syzbot reported use-after-free in mptcp_schedule_work() [1]
Issue here is that mptcp_schedule_work() schedules a work, then gets a refcount on sk->sk_refcnt if the work was scheduled. This refcount will be released by mptcp_worker().
[A] if (schedule_work(...)) {
[B] sock_hold(sk);
return true;
}Problem is that mptcp_worker() can run immediately and complete before [B]
We need instead :
sock_hold(sk);
if (schedule_work(...))
return true;
sock_put(sk);[1]refcount_t: addition on 0; use-after-free.
WARNING: CPU: 1 PID: 29 at lib/refcount.c:25 refcount_warn_saturate+0xfa/0x1d0 lib/refcount.c:25 Call Trace: <TASK> __refcount_add include/linux/refcount.h:-1 [inline] __refcount_inc include/linux/refcount.h:366 [inline] refcount_inc include/linux/refcount.h:383 [inline] sock_hold include/net/sock.h:816 [inline] mptcp_schedule_work+0x164/0x1a0 net/mptcp/protocol.c:943 mptcp_tout_timer+0x21/0xa0 net/mptcp/protocol.c:2316 call_timer_fn+0x17e/0x5f0 kernel/time/timer.c:1747 expire_timers kernel/time/timer.c:1798 [inline] __run_timers kernel/time/timer.c:2372 [inline] __run_timer_base+0x648/0x970 kernel/time/timer.c:2384 run_timer_base kernel/time/timer.c:2393 [inline] run_timer_softirq+0xb7/0x180 kernel/time/timer.c:2403 handle_softirqs+0x22f/0x710 kernel/softirq.c:622 __do_softirq kernel/softirq.c:656 [inline] run_ktimerd+0xcf/0x190 kernel/softirq.c:1138 smpboot_thread_fn+0x542/0xa60 kernel/smpboot.c:160 kthread+0x711/0x8a0 kernel/kthread.c:463 ret_from_fork+0x4bc/0x870 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
net/mptcp/protocol.c +12 -7
@@ -935,14 +935,19 @@ static void mptcp_reset_rtx_timer(struct sock *sk)bool mptcp_schedule_work (struct sock *sk) { -if (inet_sk_state_load (sk) !=TCP_CLOSE && -schedule_work (&mptcp_sk (sk)->work)) { -/* each subflow already holds a reference to the sk, and the -* workqueue is invoked by a subflow, so sk can't go away here. -*/ -sock_hold (sk); +if (inet_sk_state_load (sk) ==TCP_CLOSE ) +return false; + +/* Get a reference on this socket, mptcp_worker() will release it. +* As mptcp_worker() might complete before us, we can not avoid +* a sock_hold()/sock_put() if schedule_work() returns false. +*/ +sock_hold (sk); + +if (schedule_work (&mptcp_sk (sk)->work))return true; - } + +sock_put (sk);return false; }
Sasha Levin
maintainerPATCH 1/2 mptcp: introduce mptcp_schedule_work
From: Paolo Abeni <[email protected]>
[ Upstream commit ba8f48f7a4d79352b764ace585b5f602ef940be0 ]
remove some of code duplications an allow preventing rescheduling on close.
Stable-dep-of: 035bca3f017e ("mptcp: fix race condition in mptcp_schedule_work()")
--- net/mptcp/pm.c | 3 +-- net/mptcp/protocol.c | 36 ++++++++++++++++++++++-------------- net/mptcp/protocol.h | 1 + 3 files changed, 24 insertions(+), 16 deletions(-)
net/mptcp/pm.c +1 -2
@@ -89,8 +89,7 @@ static bool mptcp_pm_schedule_work(struct mptcp_sock *msk,return false; msk->pm.status |=BIT (new_status); -if (schedule_work (&msk->work)) -sock_hold ((struct sock *)msk); +mptcp_schedule_work ((struct sock *)msk);return true; }
net/mptcp/protocol.c +22 -14
@@ -641,9 +641,8 @@ static bool move_skbs_to_msk(struct mptcp_sock *msk, struct sock *ssk)* this is not a good place to change state. Let the workqueue * do it. */ -if (mptcp_pending_data_fin (sk,NULL ) && -schedule_work (&msk->work)) -sock_hold (sk); +if (mptcp_pending_data_fin (sk,NULL )) +mptcp_schedule_work (sk); }spin_unlock_bh (&sk->sk_lock.slock);
@@ -715,23 +714,32 @@ static void mptcp_reset_timer(struct sock *sk)sk_reset_timer (sk, &icsk->icsk_retransmit_timer, jiffies + tout); } +bool mptcp_schedule_work (struct sock *sk) +{ +if (inet_sk_state_load (sk) !=TCP_CLOSE && +schedule_work (&mptcp_sk (sk)->work)) { +/* each subflow already holds a reference to the sk, and the +* workqueue is invoked by a subflow, so sk can't go away here. +*/ +sock_hold (sk); +return true; + } +return false; +} +void mptcp_data_acked (struct sock *sk) {mptcp_reset_timer (sk);if ((!test_bit (MPTCP_SEND_SPACE , &mptcp_sk (sk)->flags) || - (inet_sk_state_load (sk) !=TCP_ESTABLISHED )) && -schedule_work (&mptcp_sk (sk)->work)) -sock_hold (sk); + (inet_sk_state_load (sk) !=TCP_ESTABLISHED ))) +mptcp_schedule_work (sk); }void mptcp_subflow_eof (struct sock *sk) { -struct mptcp_sock *msk =mptcp_sk (sk); - -if (!test_and_set_bit (MPTCP_WORK_EOF , &msk->flags) && -schedule_work (&msk->work)) -sock_hold (sk); +if (!test_and_set_bit (MPTCP_WORK_EOF , &mptcp_sk (sk)->flags)) +mptcp_schedule_work (sk); }static void mptcp_check_for_eof (struct mptcp_sock *msk)
@@ -1643,8 +1651,7 @@ static void mptcp_retransmit_handler(struct sock *sk)mptcp_stop_timer (sk); }else {set_bit (MPTCP_WORK_RTX , &msk->flags); -if (schedule_work (&msk->work)) -sock_hold (sk); +mptcp_schedule_work (sk); } }
@@ -2503,7 +2510,8 @@ static void mptcp_release_cb(struct sock *sk)struct sock *ssk; ssk =mptcp_subflow_recv_lookup (msk); -if (!ssk || !schedule_work (&msk->work)) +if (!ssk || sk->sk_state ==TCP_CLOSE || + !schedule_work (&msk->work))__sock_put (sk); }
net/mptcp/protocol.h +1 -0
@@ -410,6 +410,7 @@ static inline bool mptcp_is_fully_established(struct sock *sk)void mptcp_rcv_space_init (struct mptcp_sock *msk,const struct sock *ssk);void mptcp_data_ready (struct sock *sk,struct sock *ssk);bool mptcp_finish_join (struct sock *sk); +bool mptcp_schedule_work (struct sock *sk);void mptcp_data_acked (struct sock *sk);void mptcp_subflow_eof (struct sock *sk);bool mptcp_update_rcv_data_fin (struct mptcp_sock *msk,u64 data_fin_seq,bool use_64bit);
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 2/2 mptcp: fix race condition in mptcp_schedule_work()
From: Eric Dumazet <[email protected]>
[ Upstream commit 035bca3f017ee9dea3a5a756e77a6f7138cc6eea ]
syzbot reported use-after-free in mptcp_schedule_work() [1]
Issue here is that mptcp_schedule_work() schedules a work, then gets a refcount on sk->sk_refcnt if the work was scheduled. This refcount will be released by mptcp_worker().
[A] if (schedule_work(...)) {
[B] sock_hold(sk);
return true;
}Problem is that mptcp_worker() can run immediately and complete before [B]
We need instead :
sock_hold(sk);
if (schedule_work(...))
return true;
sock_put(sk);[1]refcount_t: addition on 0; use-after-free.
WARNING: CPU: 1 PID: 29 at lib/refcount.c:25 refcount_warn_saturate+0xfa/0x1d0 lib/refcount.c:25 Call Trace: <TASK> __refcount_add include/linux/refcount.h:-1 [inline] __refcount_inc include/linux/refcount.h:366 [inline] refcount_inc include/linux/refcount.h:383 [inline] sock_hold include/net/sock.h:816 [inline] mptcp_schedule_work+0x164/0x1a0 net/mptcp/protocol.c:943 mptcp_tout_timer+0x21/0xa0 net/mptcp/protocol.c:2316 call_timer_fn+0x17e/0x5f0 kernel/time/timer.c:1747 expire_timers kernel/time/timer.c:1798 [inline] __run_timers kernel/time/timer.c:2372 [inline] __run_timer_base+0x648/0x970 kernel/time/timer.c:2384 run_timer_base kernel/time/timer.c:2393 [inline] run_timer_softirq+0xb7/0x180 kernel/time/timer.c:2403 handle_softirqs+0x22f/0x710 kernel/softirq.c:622 __do_softirq kernel/softirq.c:656 [inline] run_ktimerd+0xcf/0x190 kernel/softirq.c:1138 smpboot_thread_fn+0x542/0xa60 kernel/smpboot.c:160 kthread+0x711/0x8a0 kernel/kthread.c:463 ret_from_fork+0x4bc/0x870 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
--- net/mptcp/protocol.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
net/mptcp/protocol.c +12 -7
@@ -716,14 +716,19 @@ static void mptcp_reset_timer(struct sock *sk)bool mptcp_schedule_work (struct sock *sk) { -if (inet_sk_state_load (sk) !=TCP_CLOSE && -schedule_work (&mptcp_sk (sk)->work)) { -/* each subflow already holds a reference to the sk, and the -* workqueue is invoked by a subflow, so sk can't go away here. -*/ -sock_hold (sk); +if (inet_sk_state_load (sk) ==TCP_CLOSE ) +return false; + +/* Get a reference on this socket, mptcp_worker() will release it. +* As mptcp_worker() might complete before us, we can not avoid +* a sock_hold()/sock_put() if schedule_work() returns false. +*/ +sock_hold (sk); + +if (schedule_work (&mptcp_sk (sk)->work))return true; - } + +sock_put (sk);return false; }
Signature · 1 line
2.51.0