FAILED: patch "[PATCH] mptcp: fix MSG_PEEK stream corruption" failed to apply to 6.12-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.12-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-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 8e04ce45a8db7a080220e86e249198fa676b83dc
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2025110208-pond-pouring-512d@gregkh' --subject-prefix 'PATCH 6.12.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 8e04ce45a8db7a080220e86e249198fa676b83dc Mon Sep 17 00:00:00 2001
From: Paolo Abeni <[email protected]>
Date: Tue, 28 Oct 2025 09:16:53 +0100
Subject: [PATCH] mptcp: fix MSG_PEEK stream corruption
If a MSG_PEEK | MSG_WAITALL read operation consumes all the bytes in the receive queue and recvmsg() need to waits for more data - i.e. it's a blocking one - upon arrival of the next packet the MPTCP protocol will start again copying the oldest data present in the receive queue, corrupting the data stream.
Address the issue explicitly tracking the peeked sequence number, restarting from the last peeked byte.
net/mptcp/protocol.c +25 -13
@@ -1945,22 +1945,36 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)static void mptcp_rcv_space_adjust (struct mptcp_sock *msk,int copied); -static int __mptcp_recvmsg_mskq (struct sock *sk, -struct msghdr *msg, -size_t len,int flags, +static int __mptcp_recvmsg_mskq (struct sock *sk,struct msghdr *msg, +size_t len,int flags,int copied_total,struct scm_timestamping_internal *tss,int *cmsg_flags) {struct mptcp_sock *msk =mptcp_sk (sk);struct sk_buff *skb, *tmp; +int total_data_len =0 ;int copied =0 ; skb_queue_walk_safe(&sk->sk_receive_queue, skb, tmp) { -u32 offset =MPTCP_SKB_CB (skb)->offset; +u32 delta, offset =MPTCP_SKB_CB (skb)->offset;u32 data_len = skb->len - offset; -u32 count =min_t (size_t, len - copied, data_len); +u32 count;int err; +if (flags &MSG_PEEK ) { +/* skip already peeked skbs */ +if (total_data_len + data_len <= copied_total) { + total_data_len += data_len; +continue ; + } + +/* skip the already peeked data in the current skb */ + delta = copied_total - total_data_len; + offset += delta; + data_len -= delta; + } + + count =min_t (size_t, len - copied, data_len);if (!(flags &MSG_TRUNC )) { err =skb_copy_datagram_msg (skb, offset, msg, count);if (unlikely (err <0 )) {
@@ -1977,16 +1991,14 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, copied += count; -if (count < data_len) { -if (!(flags &MSG_PEEK )) { +if (!(flags &MSG_PEEK )) { + msk->bytes_consumed += count; +if (count < data_len) {MPTCP_SKB_CB (skb)->offset += count;MPTCP_SKB_CB (skb)->map_seq += count; - msk->bytes_consumed += count; +break ; } -break ; - } -if (!(flags &MSG_PEEK )) {/* avoid the indirect call, we know the destructor is sock_rfree */ skb->destructor =NULL ; skb->sk =NULL ;
@@ -1994,7 +2006,6 @@ static int __mptcp_recvmsg_mskq(struct sock *sk,sk_mem_uncharge (sk, skb->truesize);__skb_unlink (skb, &sk->sk_receive_queue);skb_attempt_defer_free (skb); - msk->bytes_consumed += count; }if (copied >= len)
@@ -2191,7 +2202,8 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,while (copied < len) {int err, bytes_read; - bytes_read =__mptcp_recvmsg_mskq (sk, msg, len - copied, flags, &tss, &cmsg_flags); + bytes_read =__mptcp_recvmsg_mskq (sk, msg, len - copied, flags, + copied, &tss, &cmsg_flags);if (unlikely (bytes_read <0 )) {if (!copied) copied = bytes_read;
Sasha Levin
maintainerPATCH 1/4 mptcp: move the whole rx path under msk socket lock protection
From: Paolo Abeni <[email protected]>
[ Upstream commit bc68b0efa1bf923cef1294a631d8e7416c7e06e4 ]
After commit c2e6048fa1cf ("mptcp: fix race in release_cb") we can move the whole MPTCP rx path under the socket lock leveraging the release_cb.
We can drop a bunch of spin_lock pairs in the receive functions, use a single receive queue and invoke __mptcp_move_skbs only when subflows ask for it.
This will allow more cleanup in the next patch.
Some changes are worth specific mention:
The msk rcvbuf update now always happens under both the msk and the subflow socket lock: we can drop a bunch of ONCE annotation and consolidate the checks.
When the skbs move is delayed at msk release callback time, even the msk rcvbuf update is delayed; additionally take care of such action in __mptcp_move_skbs().
Stable-dep-of: 8e04ce45a8db ("mptcp: fix MSG_PEEK stream corruption")
--- net/mptcp/fastopen.c | 1 + net/mptcp/protocol.c | 123 ++++++++++++++++++++----------------------- net/mptcp/protocol.h | 2 +- 3 files changed, 60 insertions(+), 66 deletions(-)
net/mptcp/fastopen.c +1 -0
@@ -49,6 +49,7 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subfMPTCP_SKB_CB (skb)->has_rxtstamp =TCP_SKB_CB (skb)->has_rxtstamp;mptcp_data_lock (sk); +DEBUG_NET_WARN_ON_ONCE (sock_owned_by_user_nocheck (sk));mptcp_set_owner_r (skb, sk);__skb_queue_tail (&sk->sk_receive_queue, skb);
net/mptcp/protocol.c +58 -65
266 lines not on this page · raw message
net/mptcp/protocol.h +1 -1
@@ -124,6 +124,7 @@#define MPTCP_FLUSH_JOIN_LIST 5#define MPTCP_SYNC_STATE 6#define MPTCP_SYNC_SNDBUF 7 +#define MPTCP_DEQUEUE 8struct mptcp_skb_cb {u64 map_seq;
@@ -324,7 +325,6 @@ struct mptcp_sock {struct work_struct work;struct sk_buff *ooo_last_skb;struct rb_root out_of_order_queue; -struct sk_buff_head receive_queue;struct list_head conn_list;struct list_head rtx_queue;struct mptcp_data_frag *first_pending;
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 2/4 mptcp: cleanup mem accounting
From: Paolo Abeni <[email protected]>
[ Upstream commit 6639498ed85fdb135dfb0dfbcc0f540b2d4ad6a6 ]
After the previous patch, updating sk_forward_memory is cheap and we can drop a lot of complexity from the MPTCP memory accounting, removing the custom fwd mem allocations for rmem.
Stable-dep-of: 8e04ce45a8db ("mptcp: fix MSG_PEEK stream corruption")
--- net/mptcp/fastopen.c | 2 +- net/mptcp/protocol.c | 115 +++---------------------------------------- net/mptcp/protocol.h | 4 +- 3 files changed, 10 insertions(+), 111 deletions(-)
net/mptcp/fastopen.c +1 -1
@@ -51,7 +51,7 @@ void mptcp_fastopen_subflow_synack_set_params(struct mptcp_subflow_context *subfmptcp_data_lock (sk);DEBUG_NET_WARN_ON_ONCE (sock_owned_by_user_nocheck (sk)); -mptcp_set_owner_r (skb, sk); +skb_set_owner_r (skb, sk);__skb_queue_tail (&sk->sk_receive_queue, skb);mptcp_sk (sk)->bytes_received += skb->len;
net/mptcp/protocol.c +8 -107
212 lines not on this page · raw message
net/mptcp/protocol.h +1 -3
@@ -280,7 +280,6 @@ struct mptcp_sock {u64 rcv_data_fin_seq;u64 bytes_retrans;u64 bytes_consumed; -int rmem_fwd_alloc;int snd_burst;int old_wspace;u64 recovery_snd_nxt;/* in recovery mode accept up to this seq;
@@ -295,7 +294,6 @@ struct mptcp_sock {u32 last_ack_recv;unsigned long timer_ival;u32 token; -int rmem_released;unsigned long flags;unsigned long cb_flags;bool recovery;/* closing subflow write queue reinjected */
@@ -392,7 +390,7 @@ static inline void msk_owned_by_me(const struct mptcp_sock *msk)*/ static inline int __mptcp_rmem (const struct sock *sk) { -return atomic_read (&sk->sk_rmem_alloc) -READ_ONCE (mptcp_sk (sk)->rmem_released); +return atomic_read (&sk->sk_rmem_alloc); }static inline int mptcp_win_from_space (const struct sock *sk,int space)
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 3/4 mptcp: leverage skb deferral free
In reply to Sasha LevinFrom: Paolo Abeni <[email protected]>
[ Upstream commit 9aa59323f2709370cb4f01acbba599a9167f317b ]
Usage of the skb deferral API is straight-forward; with multiple subflows actives this allow moving part of the received application load into multiple CPUs.
Also fix a typo in the related comment.
Stable-dep-of: 8e04ce45a8db ("mptcp: fix MSG_PEEK stream corruption")
--- net/mptcp/protocol.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
net/mptcp/protocol.c +3 -2
@@ -1944,12 +1944,13 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, }if (!(flags &MSG_PEEK )) { -/* avoid the indirect call, we know the destructor is sock_wfree */ +/* avoid the indirect call, we know the destructor is sock_rfree */ skb->destructor =NULL ; + skb->sk =NULL ;atomic_sub (skb->truesize, &sk->sk_rmem_alloc);sk_mem_uncharge (sk, skb->truesize);__skb_unlink (skb, &sk->sk_receive_queue); -__kfree_skb (skb); +skb_attempt_defer_free (skb); msk->bytes_consumed += count; }
Signature · 1 line
2.51.0
Sasha Levin
maintainerPATCH 4/4 mptcp: fix MSG_PEEK stream corruption
In reply to Sasha LevinFrom: Paolo Abeni <[email protected]>
[ Upstream commit 8e04ce45a8db7a080220e86e249198fa676b83dc ]
If a MSG_PEEK | MSG_WAITALL read operation consumes all the bytes in the receive queue and recvmsg() need to waits for more data - i.e. it's a blocking one - upon arrival of the next packet the MPTCP protocol will start again copying the oldest data present in the receive queue, corrupting the data stream.
Address the issue explicitly tracking the peeked sequence number, restarting from the last peeked byte.
--- net/mptcp/protocol.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-)
net/mptcp/protocol.c +25 -13
@@ -1902,22 +1902,36 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)static void mptcp_rcv_space_adjust (struct mptcp_sock *msk,int copied); -static int __mptcp_recvmsg_mskq (struct sock *sk, -struct msghdr *msg, -size_t len,int flags, +static int __mptcp_recvmsg_mskq (struct sock *sk,struct msghdr *msg, +size_t len,int flags,int copied_total,struct scm_timestamping_internal *tss,int *cmsg_flags) {struct mptcp_sock *msk =mptcp_sk (sk);struct sk_buff *skb, *tmp; +int total_data_len =0 ;int copied =0 ; skb_queue_walk_safe(&sk->sk_receive_queue, skb, tmp) { -u32 offset =MPTCP_SKB_CB (skb)->offset; +u32 delta, offset =MPTCP_SKB_CB (skb)->offset;u32 data_len = skb->len - offset; -u32 count =min_t (size_t, len - copied, data_len); +u32 count;int err; +if (flags &MSG_PEEK ) { +/* skip already peeked skbs */ +if (total_data_len + data_len <= copied_total) { + total_data_len += data_len; +continue ; + } + +/* skip the already peeked data in the current skb */ + delta = copied_total - total_data_len; + offset += delta; + data_len -= delta; + } + + count =min_t (size_t, len - copied, data_len);if (!(flags &MSG_TRUNC )) { err =skb_copy_datagram_msg (skb, offset, msg, count);if (unlikely (err <0 )) {
@@ -1934,16 +1948,14 @@ static int __mptcp_recvmsg_mskq(struct sock *sk, copied += count; -if (count < data_len) { -if (!(flags &MSG_PEEK )) { +if (!(flags &MSG_PEEK )) { + msk->bytes_consumed += count; +if (count < data_len) {MPTCP_SKB_CB (skb)->offset += count;MPTCP_SKB_CB (skb)->map_seq += count; - msk->bytes_consumed += count; +break ; } -break ; - } -if (!(flags &MSG_PEEK )) {/* avoid the indirect call, we know the destructor is sock_rfree */ skb->destructor =NULL ; skb->sk =NULL ;
@@ -1951,7 +1963,6 @@ static int __mptcp_recvmsg_mskq(struct sock *sk,sk_mem_uncharge (sk, skb->truesize);__skb_unlink (skb, &sk->sk_receive_queue);skb_attempt_defer_free (skb); - msk->bytes_consumed += count; }if (copied >= len)
@@ -2149,7 +2160,8 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,while (copied < len) {int err, bytes_read; - bytes_read =__mptcp_recvmsg_mskq (sk, msg, len - copied, flags, &tss, &cmsg_flags); + bytes_read =__mptcp_recvmsg_mskq (sk, msg, len - copied, flags, + copied, &tss, &cmsg_flags);if (unlikely (bytes_read <0 )) {if (!copied) copied = bytes_read;
Signature · 1 line
2.51.0
Matthieu Baerts (NGI0)
maintainerPATCH 1/1 mptcp: fix MSG_PEEK stream corruption
In reply to [email protected]From: Paolo Abeni <[email protected]>
[ Upstream commit 8e04ce45a8db7a080220e86e249198fa676b83dc ]
If a MSG_PEEK | MSG_WAITALL read operation consumes all the bytes in the receive queue and recvmsg() need to waits for more data - i.e. it's a blocking one - upon arrival of the next packet the MPTCP protocol will start again copying the oldest data present in the receive queue, corrupting the data stream.
Address the issue explicitly tracking the peeked sequence number, restarting from the last peeked byte.
---
Note: this is the patch Sasha sent for the v6.6 which applies on v6.12 without conflicts. On v6.12, Sasha sent another version with dependences that caused some issues, see:
https://lore.kernel.org/[email protected]
--- net/mptcp/protocol.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-)
net/mptcp/protocol.c +25 -11
@@ -1977,19 +1977,35 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied);static int __mptcp_recvmsg_mskq (struct mptcp_sock *msk,struct msghdr *msg, -size_t len,int flags, +size_t len,int flags,int copied_total,struct scm_timestamping_internal *tss,int *cmsg_flags) {struct sk_buff *skb, *tmp; +int total_data_len =0 ;int copied =0 ; skb_queue_walk_safe(&msk->receive_queue, skb, tmp) { -u32 offset =MPTCP_SKB_CB (skb)->offset; +u32 delta, offset =MPTCP_SKB_CB (skb)->offset;u32 data_len = skb->len - offset; -u32 count =min_t (size_t, len - copied, data_len); +u32 count;int err; +if (flags &MSG_PEEK ) { +/* skip already peeked skbs */ +if (total_data_len + data_len <= copied_total) { + total_data_len += data_len; +continue ; + } + +/* skip the already peeked data in the current skb */ + delta = copied_total - total_data_len; + offset += delta; + data_len -= delta; + } + + count =min_t (size_t, len - copied, data_len); +if (!(flags &MSG_TRUNC )) { err =skb_copy_datagram_msg (skb, offset, msg, count);if (unlikely (err <0 )) {
@@ -2006,22 +2022,19 @@ static int __mptcp_recvmsg_mskq(struct mptcp_sock *msk, copied += count; -if (count < data_len) { -if (!(flags &MSG_PEEK )) { +if (!(flags &MSG_PEEK )) { + msk->bytes_consumed += count; +if (count < data_len) {MPTCP_SKB_CB (skb)->offset += count;MPTCP_SKB_CB (skb)->map_seq += count; - msk->bytes_consumed += count; +break ; } -break ; - } -if (!(flags &MSG_PEEK )) {/* we will bulk release the skb memory later */ skb->destructor =NULL ;WRITE_ONCE (msk->rmem_released, msk->rmem_released + skb->truesize);__skb_unlink (skb, &msk->receive_queue);__kfree_skb (skb); - msk->bytes_consumed += count; }if (copied >= len)
@@ -2245,7 +2258,8 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,while (copied < len) {int err, bytes_read; - bytes_read =__mptcp_recvmsg_mskq (msk, msg, len - copied, flags, &tss, &cmsg_flags); + bytes_read =__mptcp_recvmsg_mskq (msk, msg, len - copied, flags, + copied, &tss, &cmsg_flags);if (unlikely (bytes_read <0 )) {if (!copied) copied = bytes_read;
Signature · 1 line
2.51.0
Patch "mptcp: fix MSG_PEEK stream corruption" has been added to the 6.12-stable tree
This is a note to let you know that I've just added the patch titled
mptcp: fix MSG_PEEK stream corruption
to the 6.12-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
mptcp-fix-msg_peek-stream-corruption.patch
and it can be found in the queue-6.12 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
From [email protected] Tue Nov 4 13:17:04 2025
From: "Matthieu Baerts (NGI0)" <[email protected]>
Date: Tue, 4 Nov 2025 13:15:16 +0100
Subject: mptcp: fix MSG_PEEK stream corruption
To: [email protected], [email protected]
Cc: MPTCP Upstream <[email protected]>, Paolo Abeni <[email protected]>, Geliang Tang <[email protected]>, Mat Martineau <[email protected]>, "Matthieu Baerts (NGI0)" <[email protected]>, Jakub Kicinski <[email protected]>, Sasha Levin <[email protected]>
Message-ID: <[email protected]>
From: Paolo Abeni <[email protected]>
[ Upstream commit 8e04ce45a8db7a080220e86e249198fa676b83dc ]
If a MSG_PEEK | MSG_WAITALL read operation consumes all the bytes in the receive queue and recvmsg() need to waits for more data - i.e. it's a blocking one - upon arrival of the next packet the MPTCP protocol will start again copying the oldest data present in the receive queue, corrupting the data stream.
Address the issue explicitly tracking the peeked sequence number, restarting from the last peeked byte.
---
Note: this is the patch Sasha sent for the v6.6 which applies on v6.12 without conflicts. On v6.12, Sasha sent another version with dependences that caused some issues, see:
https://lore.kernel.org/[email protected]
--- net/mptcp/protocol.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-)
net/mptcp/protocol.c +25 -11
@@ -1977,19 +1977,35 @@ static void mptcp_rcv_space_adjust(strucstatic int __mptcp_recvmsg_mskq (struct mptcp_sock *msk,struct msghdr *msg, -size_t len,int flags, +size_t len,int flags,int copied_total,struct scm_timestamping_internal *tss,int *cmsg_flags) {struct sk_buff *skb, *tmp; +int total_data_len =0 ;int copied =0 ; skb_queue_walk_safe(&msk->receive_queue, skb, tmp) { -u32 offset =MPTCP_SKB_CB (skb)->offset; +u32 delta, offset =MPTCP_SKB_CB (skb)->offset;u32 data_len = skb->len - offset; -u32 count =min_t (size_t, len - copied, data_len); +u32 count;int err; +if (flags &MSG_PEEK ) { +/* skip already peeked skbs */ +if (total_data_len + data_len <= copied_total) { + total_data_len += data_len; +continue ; + } + +/* skip the already peeked data in the current skb */ + delta = copied_total - total_data_len; + offset += delta; + data_len -= delta; + } + + count =min_t (size_t, len - copied, data_len); +if (!(flags &MSG_TRUNC )) { err =skb_copy_datagram_msg (skb, offset, msg, count);if (unlikely (err <0 )) {
@@ -2006,22 +2022,19 @@ static int __mptcp_recvmsg_mskq(struct m copied += count; -if (count < data_len) { -if (!(flags &MSG_PEEK )) { +if (!(flags &MSG_PEEK )) { + msk->bytes_consumed += count; +if (count < data_len) {MPTCP_SKB_CB (skb)->offset += count;MPTCP_SKB_CB (skb)->map_seq += count; - msk->bytes_consumed += count; +break ; } -break ; - } -if (!(flags &MSG_PEEK )) {/* we will bulk release the skb memory later */ skb->destructor =NULL ;WRITE_ONCE (msk->rmem_released, msk->rmem_released + skb->truesize);__skb_unlink (skb, &msk->receive_queue);__kfree_skb (skb); - msk->bytes_consumed += count; }if (copied >= len)
@@ -2245,7 +2258,8 @@ static int mptcp_recvmsg(struct sock *skwhile (copied < len) {int err, bytes_read; - bytes_read =__mptcp_recvmsg_mskq (msk, msg, len - copied, flags, &tss, &cmsg_flags); + bytes_read =__mptcp_recvmsg_mskq (msk, msg, len - copied, flags, + copied, &tss, &cmsg_flags);if (unlikely (bytes_read <0 )) {if (!copied) copied = bytes_read;
Patches currently in stable-queue which might be from [email protected] are
queue-6.12/selftests-mptcp-join-endpoints-longer-transfer.patch queue-6.12/selftests-mptcp-connect-trunc-read-all-recv-data.patch queue-6.12/selftests-mptcp-join-rm-set-backup-flag.patch queue-6.12/selftests-mptcp-connect-fix-fallback-note-due-to-ooo.patch queue-6.12/mptcp-fix-msg_peek-stream-corruption.patch queue-6.12/selftests-mptcp-join-properly-kill-background-tasks.patch queue-6.12/selftests-mptcp-join-userspace-longer-transfer.patch queue-6.12/gcov-add-support-for-gcc-15.patch