FAILED: patch "[PATCH] mptcp: close TOCTOU race while computing rcv_wnd" failed to apply to 5.15-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.15-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.15.y
git checkout FETCH_HEAD
git cherry-pick -x 8ab24fdebc369c0dfb90f82c1650b1e66662bb45
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026061521-laborious-platinum-e85f@gregkh' --subject-prefix 'PATCH 5.15.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 8ab24fdebc369c0dfb90f82c1650b1e66662bb45 Mon Sep 17 00:00:00 2001
From: Paolo Abeni <[email protected]>
Date: Tue, 2 Jun 2026 22:14:10 +1000
Subject: [PATCH] mptcp: close TOCTOU race while computing rcv_wnd
The MPTCP output path access locklessly the MPTCP-level ack_seq in multiple times, using possibly different values for the data_ack in the DSS option and to compute the announced rcv wnd for the same packet.
Refactor the cote to avoid inconsistencies which may confuse the peer. Also ensure that the MPTCP level rcv wnd is updated only when the egress packet actually contains a DSS ack.
net/mptcp/options.c +18 -18
@@ -570,7 +570,6 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,struct mptcp_ext *mpext;unsigned int ack_size;bool ret = false; -u64 ack_seq; opts->csum_reqd =READ_ONCE (msk->csum_enabled); mpext = skb ?mptcp_get_ext (skb) :NULL ;
@@ -601,14 +600,11 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,return ret; } - ack_seq =READ_ONCE (msk->ack_seq);if (READ_ONCE (msk->use_64bit_ack)) { ack_size =TCPOLEN_MPTCP_DSS_ACK64 ; - opts->ext_copy.data_ack = ack_seq; opts->ext_copy.ack64 =1 ; }else { ack_size =TCPOLEN_MPTCP_DSS_ACK32 ; - opts->ext_copy.data_ack32 = (uint32_t )ack_seq; opts->ext_copy.ack64 =0 ; } opts->ext_copy.use_ack =1 ;
@@ -1297,19 +1293,14 @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)return true; } -static void mptcp_set_rwin (struct tcp_sock *tp,struct tcphdr *th) +static u64 mptcp_set_rwin (struct mptcp_sock *msk,struct tcp_sock *tp, +struct tcphdr *th,u64 ack_seq) {const struct sock *ssk = (const struct sock *)tp; -struct mptcp_subflow_context *subflow; -u64 ack_seq, rcv_wnd_old, rcv_wnd_new; -struct mptcp_sock *msk; +u64 rcv_wnd_old, rcv_wnd_new;u32 new_win;u64 win; - subflow =mptcp_subflow_ctx (ssk); - msk =mptcp_sk (subflow->conn); - - ack_seq =READ_ONCE (msk->ack_seq); rcv_wnd_new = ack_seq + tp->rcv_wnd; rcv_wnd_old =atomic64_read (&msk->rcv_wnd_sent);
@@ -1362,7 +1353,7 @@ static void mptcp_set_rwin(struct tcp_sock *tp, struct tcphdr *th) update_wspace:WRITE_ONCE (msk->old_wspace, tp->rcv_wnd); - subflow->rcv_wnd_sent = rcv_wnd_new; +return rcv_wnd_new; }static void mptcp_track_rwin (struct tcp_sock *tp)
@@ -1474,13 +1465,25 @@ void mptcp_write_options(struct tcphdr *th, __be32 *ptr, struct tcp_sock *tp, *ptr++ =mptcp_option (MPTCPOPT_DSS , len,0 , flags);if (mpext->use_ack) { +struct mptcp_sock *msk; +u64 ack_seq; + +/* DSS option is set only by mptcp_established_options, +* the caller is __tcp_transmit_skb() and ssk is always +* not NULL. +*/ + subflow =mptcp_subflow_ctx (ssk); + msk =mptcp_sk (subflow->conn); + ack_seq =READ_ONCE (msk->ack_seq);if (mpext->ack64) { -put_unaligned_be64 (mpext->data_ack, ptr); +put_unaligned_be64 (ack_seq, ptr); ptr +=2 ; }else { -put_unaligned_be32 (mpext->data_ack32, ptr); +put_unaligned_be32 (ack_seq, ptr); ptr +=1 ; } + subflow->rcv_wnd_sent =mptcp_set_rwin (msk, tp, th, + ack_seq); }if (mpext->use_map) {
@@ -1708,9 +1711,6 @@ void mptcp_write_options(struct tcphdr *th, __be32 *ptr, struct tcp_sock *tp, i +=4 ; } } - -if (tp) -mptcp_set_rwin (tp, th); }__be32 mptcp_get_reset_option (const struct sk_buff *skb)
Sasha Levin
maintainerPATCH 1/1 mptcp: close TOCTOU race while computing rcv_wnd
From: Paolo Abeni <[email protected]>
[ Upstream commit 8ab24fdebc369c0dfb90f82c1650b1e66662bb45 ]
The MPTCP output path access locklessly the MPTCP-level ack_seq in multiple times, using possibly different values for the data_ack in the DSS option and to compute the announced rcv wnd for the same packet.
Refactor the cote to avoid inconsistencies which may confuse the peer. Also ensure that the MPTCP level rcv wnd is updated only when the egress packet actually contains a DSS ack.
--- net/mptcp/options.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-)
net/mptcp/options.c +17 -12
@@ -555,7 +555,6 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,struct mptcp_ext *mpext;unsigned int ack_size;bool ret = false; -u64 ack_seq; opts->csum_reqd =READ_ONCE (msk->csum_enabled); mpext = skb ?mptcp_get_ext (skb) :NULL ;
@@ -587,14 +586,11 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,return ret; } - ack_seq =READ_ONCE (msk->ack_seq);if (READ_ONCE (msk->use_64bit_ack)) { ack_size =TCPOLEN_MPTCP_DSS_ACK64 ; - opts->ext_copy.data_ack = ack_seq; opts->ext_copy.ack64 =1 ; }else { ack_size =TCPOLEN_MPTCP_DSS_ACK32 ; - opts->ext_copy.data_ack32 = (uint32_t )ack_seq; opts->ext_copy.ack64 =0 ; } opts->ext_copy.use_ack =1 ;
@@ -1235,17 +1231,16 @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)return true; } -static void mptcp_set_rwin (const struct tcp_sock *tp) +static void mptcp_set_rwin (const struct tcp_sock *tp,u64 ack_seq) {const struct sock *ssk = (const struct sock *)tp;struct mptcp_subflow_context *subflow;struct mptcp_sock *msk; -u64 ack_seq; subflow =mptcp_subflow_ctx (ssk); msk =mptcp_sk (subflow->conn); - ack_seq =READ_ONCE (msk->ack_seq) + tp->rcv_wnd; + ack_seq += tp->rcv_wnd;if (after64 (ack_seq,READ_ONCE (msk->rcv_wnd_sent))) {WRITE_ONCE (msk->rcv_wnd_sent, ack_seq);
@@ -1369,13 +1364,26 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp, *ptr++ =mptcp_option (MPTCPOPT_DSS , len,0 , flags);if (mpext->use_ack) { +const struct sock *ssk = (const struct sock *)tp; +struct mptcp_subflow_context *subflow; +struct mptcp_sock *msk; +u64 ack_seq; + +/* DSS option is set only by mptcp_established_options, +* the caller is __tcp_transmit_skb() and ssk is always +* not NULL. +*/ + subflow =mptcp_subflow_ctx (ssk); + msk =mptcp_sk (subflow->conn); + ack_seq =READ_ONCE (msk->ack_seq);if (mpext->ack64) { -put_unaligned_be64 (mpext->data_ack, ptr); +put_unaligned_be64 (ack_seq, ptr); ptr +=2 ; }else { -put_unaligned_be32 (mpext->data_ack32, ptr); +put_unaligned_be32 (ack_seq, ptr); ptr +=1 ; } +mptcp_set_rwin (tp, ack_seq); }if (mpext->use_map) {
@@ -1559,9 +1567,6 @@ void mptcp_write_options(__be32 *ptr, const struct tcp_sock *tp, i +=4 ; } } - -if (tp) -mptcp_set_rwin (tp); }__be32 mptcp_get_reset_option (const struct sk_buff *skb)
Signature · 1 line
2.53.0