* [PATCH net 1/2] tcp: challenge ACK for non-exact RST in SYN-RECEIVED
2026-07-17 8:14 [PATCH net 0/2] tcp: validate RST sequence in SYN-RECEIVED Yuxiang Yang
@ 2026-07-17 8:14 ` Yuxiang Yang
2026-07-20 16:45 ` Eric Dumazet
2026-07-17 8:14 ` [PATCH net 2/2] selftests/net: packetdrill: cover RST validation " Yuxiang Yang
2026-07-23 15:40 ` [PATCH net 0/2] tcp: validate RST sequence " patchwork-bot+netdevbpf
2 siblings, 1 reply; 6+ messages in thread
From: Yuxiang Yang @ 2026-07-17 8:14 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, linux-kselftest, Eric Dumazet, Neal Cardwell,
Kuniyuki Iwashima, David S . Miller, Jakub Kicinski, Paolo Abeni,
Simon Horman, Shuah Khan, Yuxiang Yang, Yizhou Zhao, Ao Wang,
Xuewei Feng, Qi Li, Ke Xu, stable, yyxroy22
The SYN-RECEIVED request-socket path in tcp_check_req() accepts an
in-window RST without requiring SEG.SEQ to exactly match RCV.NXT. A
non-exact RST therefore removes the request instead of eliciting a
challenge ACK.
RFC 9293 section 3.10.7.4 applies the RFC 5961 reset check in
SYN-RECEIVED: an exact RST resets the connection, while a non-exact
in-window RST must trigger a challenge ACK and be dropped.
Apply that check before the ACK-field validation, following the RFC
sequence-number, RST, then ACK processing order. Factor the per-netns
challenge ACK quota out of tcp_send_challenge_ack() so request sockets
can share it. Use the request socket's send_ack() callback and its own
out-of-window ACK timestamp to send and rate-limit the response.
Reported-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
Reported-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
Reported-by: Ao Wang <wangao@seu.edu.cn>
Reported-by: Xuewei Feng <fengxw06@126.com>
Reported-by: Qi Li <qli01@tsinghua.edu.cn>
Reported-by: Ke Xu <xuke@tsinghua.edu.cn>
Fixes: 282f23c6ee34 ("tcp: implement RFC 5961 3.2")
Cc: stable@vger.kernel.org
Signed-off-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
---
include/net/tcp.h | 2 ++
net/ipv4/tcp_input.c | 56 ++++++++++++++++++++++++++++++----------
net/ipv4/tcp_minisocks.c | 12 ++++++++-
3 files changed, 56 insertions(+), 14 deletions(-)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 6d376ea4d..2c5b88953 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1974,6 +1974,8 @@ static inline void tcp_fast_path_check(struct sock *sk)
bool tcp_oow_rate_limited(struct net *net, const struct sk_buff *skb,
int mib_idx, u32 *last_oow_ack_time);
+void tcp_reqsk_send_challenge_ack(struct sock *sk, struct sk_buff *skb,
+ struct request_sock *req);
static inline void tcp_mib_init(struct net *net)
{
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 61045a888..daff93d51 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4038,24 +4038,17 @@ static void tcp_send_ack_reflect_ect(struct sock *sk, bool accecn_reflector)
__tcp_send_ack(sk, tp->rcv_nxt, flags);
}
-/* RFC 5961 7 [ACK Throttling] */
-static void tcp_send_challenge_ack(struct sock *sk, bool accecn_reflector)
+/* Consume one slot from the per-netns RFC 5961 challenge ACK quota.
+ * Returns true if a challenge ACK may be sent.
+ */
+static bool tcp_challenge_ack_allowed(struct net *net)
{
- struct tcp_sock *tp = tcp_sk(sk);
- struct net *net = sock_net(sk);
u32 count, now, ack_limit;
- /* First check our per-socket dupack rate limit. */
- if (__tcp_oow_rate_limited(net,
- LINUX_MIB_TCPACKSKIPPEDCHALLENGE,
- &tp->last_oow_ack_time))
- return;
-
ack_limit = READ_ONCE(net->ipv4.sysctl_tcp_challenge_ack_limit);
if (ack_limit == INT_MAX)
- goto send_ack;
+ return true;
- /* Then check host-wide RFC 5961 rate limit. */
now = jiffies / HZ;
if (now != READ_ONCE(net->ipv4.tcp_challenge_timestamp)) {
u32 half = (ack_limit + 1) >> 1;
@@ -4067,12 +4060,49 @@ static void tcp_send_challenge_ack(struct sock *sk, bool accecn_reflector)
count = READ_ONCE(net->ipv4.tcp_challenge_count);
if (count > 0) {
WRITE_ONCE(net->ipv4.tcp_challenge_count, count - 1);
-send_ack:
+ return true;
+ }
+ return false;
+}
+
+/* RFC 5961 7 [ACK Throttling] */
+static void tcp_send_challenge_ack(struct sock *sk, bool accecn_reflector)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct net *net = sock_net(sk);
+
+ /* First check our per-socket dupack rate limit. */
+ if (__tcp_oow_rate_limited(net,
+ LINUX_MIB_TCPACKSKIPPEDCHALLENGE,
+ &tp->last_oow_ack_time))
+ return;
+
+ /* Then check the per-netns RFC 5961 rate limit. */
+ if (tcp_challenge_ack_allowed(net)) {
NET_INC_STATS(net, LINUX_MIB_TCPCHALLENGEACK);
tcp_send_ack_reflect_ect(sk, accecn_reflector);
}
}
+/* Send a challenge ACK from a SYN-RECEIVED request socket. Uses
+ * __tcp_oow_rate_limited() directly so that an RST carrying payload
+ * cannot bypass the per-request rate limit.
+ */
+void tcp_reqsk_send_challenge_ack(struct sock *sk, struct sk_buff *skb,
+ struct request_sock *req)
+{
+ struct net *net = sock_net(sk);
+
+ if (__tcp_oow_rate_limited(net, LINUX_MIB_TCPACKSKIPPEDCHALLENGE,
+ &tcp_rsk(req)->last_oow_ack_time))
+ return;
+
+ if (tcp_challenge_ack_allowed(net)) {
+ NET_INC_STATS(net, LINUX_MIB_TCPCHALLENGEACK);
+ req->rsk_ops->send_ack(sk, skb, req);
+ }
+}
+
static void tcp_store_ts_recent(struct tcp_sock *tp)
{
tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index ddc4b17a8..6ab3e3a0b 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -833,7 +833,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
* elsewhere and is checked directly against the child socket rather
* than req because user data may have been sent out.
*/
- if ((flg & TCP_FLAG_ACK) && !fastopen &&
+ if ((flg & TCP_FLAG_ACK) && !(flg & TCP_FLAG_RST) && !fastopen &&
(TCP_SKB_CB(skb)->ack_seq !=
tcp_rsk(req)->snt_isn + 1))
return sk;
@@ -872,6 +872,16 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
flg &= ~TCP_FLAG_SYN;
}
+ /* RFC 5961 section 3.2, as clarified by RFC 9293 section
+ * 3.10.7.4, requires a challenge ACK for a non-exact
+ * in-window RST in SYN-RECEIVED.
+ */
+ if ((flg & TCP_FLAG_RST) &&
+ TCP_SKB_CB(skb)->seq != tcp_rsk(req)->rcv_nxt) {
+ tcp_reqsk_send_challenge_ack(sk, skb, req);
+ return NULL;
+ }
+
/* RFC793: "second check the RST bit" and
* "fourth, check the SYN bit"
*/
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH net 1/2] tcp: challenge ACK for non-exact RST in SYN-RECEIVED
2026-07-17 8:14 ` [PATCH net 1/2] tcp: challenge ACK for non-exact RST " Yuxiang Yang
@ 2026-07-20 16:45 ` Eric Dumazet
0 siblings, 0 replies; 6+ messages in thread
From: Eric Dumazet @ 2026-07-20 16:45 UTC (permalink / raw)
To: Yuxiang Yang
Cc: netdev, linux-kernel, linux-kselftest, Neal Cardwell,
Kuniyuki Iwashima, David S . Miller, Jakub Kicinski, Paolo Abeni,
Simon Horman, Shuah Khan, Yizhou Zhao, Ao Wang, Xuewei Feng,
Qi Li, Ke Xu, stable, yyxroy22
On Fri, Jul 17, 2026 at 10:15 AM Yuxiang Yang
<yangyx22@mails.tsinghua.edu.cn> wrote:
>
> The SYN-RECEIVED request-socket path in tcp_check_req() accepts an
> in-window RST without requiring SEG.SEQ to exactly match RCV.NXT. A
> non-exact RST therefore removes the request instead of eliciting a
> challenge ACK.
>
> RFC 9293 section 3.10.7.4 applies the RFC 5961 reset check in
> SYN-RECEIVED: an exact RST resets the connection, while a non-exact
> in-window RST must trigger a challenge ACK and be dropped.
>
> Apply that check before the ACK-field validation, following the RFC
> sequence-number, RST, then ACK processing order. Factor the per-netns
> challenge ACK quota out of tcp_send_challenge_ack() so request sockets
> can share it. Use the request socket's send_ack() callback and its own
> out-of-window ACK timestamp to send and rate-limit the response.
>
> Reported-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
> Reported-by: Yizhou Zhao <zhaoyz24@mails.tsinghua.edu.cn>
> Reported-by: Ao Wang <wangao@seu.edu.cn>
> Reported-by: Xuewei Feng <fengxw06@126.com>
> Reported-by: Qi Li <qli01@tsinghua.edu.cn>
> Reported-by: Ke Xu <xuke@tsinghua.edu.cn>
> Fixes: 282f23c6ee34 ("tcp: implement RFC 5961 3.2")
> Cc: stable@vger.kernel.org
> Signed-off-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
Note : Please do not add a Reported-by: Yuxiang Yang
<yangyx22@mails.tsinghua.edu.cn> if you are the patch author.
The amount of noise in this patch footer is quite annoying.
Reviewed-by: Eric Dumazet <edumazet@google.com>
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net 2/2] selftests/net: packetdrill: cover RST validation in SYN-RECEIVED
2026-07-17 8:14 [PATCH net 0/2] tcp: validate RST sequence in SYN-RECEIVED Yuxiang Yang
2026-07-17 8:14 ` [PATCH net 1/2] tcp: challenge ACK for non-exact RST " Yuxiang Yang
@ 2026-07-17 8:14 ` Yuxiang Yang
2026-07-20 16:48 ` Eric Dumazet
2026-07-23 15:40 ` [PATCH net 0/2] tcp: validate RST sequence " patchwork-bot+netdevbpf
2 siblings, 1 reply; 6+ messages in thread
From: Yuxiang Yang @ 2026-07-17 8:14 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, linux-kselftest, Eric Dumazet, Neal Cardwell,
Kuniyuki Iwashima, David S . Miller, Jakub Kicinski, Paolo Abeni,
Simon Horman, Shuah Khan, Yuxiang Yang, Yizhou Zhao, Ao Wang,
Xuewei Feng, Qi Li, Ke Xu, yyxroy22
Add packetdrill coverage for the RFC 9293 reset checks on request
sockets in SYN-RECEIVED. Verify that an exact RST removes the request,
a non-exact in-window RST sends a challenge ACK without removing it,
and an out-of-window RST is silently discarded.
Also cover an RST|ACK with an unacceptable ACK number to ensure RST
sequence validation runs before ACK-field validation.
Signed-off-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
---
.../packetdrill/tcp_rfc5961_rst-syn-recv.pkt | 61 +++++++++++++++++++
1 file changed, 61 insertions(+)
create mode 100644 tools/testing/selftests/net/packetdrill/tcp_rfc5961_rst-syn-recv.pkt
diff --git a/tools/testing/selftests/net/packetdrill/tcp_rfc5961_rst-syn-recv.pkt b/tools/testing/selftests/net/packetdrill/tcp_rfc5961_rst-syn-recv.pkt
new file mode 100644
index 000000000..3fc2de036
--- /dev/null
+++ b/tools/testing/selftests/net/packetdrill/tcp_rfc5961_rst-syn-recv.pkt
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// RFC 9293 Section 3.10.7.4: in SYN-RECEIVED, an exact RST resets
+// the connection. A non-exact in-window RST elicits a challenge ACK,
+// while an out-of-window RST is silently discarded.
+
+`./defaults.sh`
+
+// An exact RST removes the request socket.
+ 0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 3
+ +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+ +0 bind(3, ..., ...) = 0
+ +0 listen(3, 1) = 0
+ +0 < S 0:0(0) win 1000 <mss 1000,sackOK,nop,nop,nop,wscale 0>
+ +0 > S. 0:0(0) ack 1 <...>
+ +0 < R 1:1(0) win 1000
+ +.1 < . 1:1(0) ack 1 win 1000
+ +0 > R 1:1(0)
+ +0 close(3) = 0
+
+// A non-exact in-window RST gets a challenge ACK and the request survives.
+ +0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 3
+ +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+ +0 bind(3, ..., ...) = 0
+ +0 listen(3, 1) = 0
+ +0 < S 0:0(0) win 1000 <mss 1000,sackOK,nop,nop,nop,wscale 0>
+ +0 > S. 0:0(0) ack 1 <...>
+ +0 < R 2:2(0) win 1000
+ +0 > . 1:1(0) ack 1
+ +0 < . 1:1(0) ack 1 win 1000
+ +0 accept(3, ..., ...) = 4
+ +0 close(4) = 0
+ +0 close(3) = 0
+
+// RST sequence validation precedes ACK validation. Even an RST|ACK
+// with an unacceptable ACK value gets a challenge ACK.
+ +0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 3
+ +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+ +0 bind(3, ..., ...) = 0
+ +0 listen(3, 1) = 0
+ +0 < S 0:0(0) win 1000 <mss 1000,sackOK,nop,nop,nop,wscale 0>
+ +0 > S. 0:0(0) ack 1 <...>
+ +0 < R. 2:2(0) ack 100 win 1000
+ +0 > . 1:1(0) ack 1
+ +0 < . 1:1(0) ack 1 win 1000
+ +0 accept(3, ..., ...) = 4
+ +0 close(4) = 0
+ +0 close(3) = 0
+
+// An out-of-window RST is silent and does not remove the request.
+ +0 socket(..., SOCK_STREAM|SOCK_NONBLOCK, IPPROTO_TCP) = 3
+ +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+ +0 bind(3, ..., ...) = 0
+ +0 listen(3, 1) = 0
+ +0 < S 0:0(0) win 1000 <mss 1000,sackOK,nop,nop,nop,wscale 0>
+ +0 > S. 0:0(0) ack 1 <...>
+ +0 < R 100001:100001(0) win 1000
+ +.1 < . 1:1(0) ack 1 win 1000
+ +0 accept(3, ..., ...) = 4
+ +0 close(4) = 0
+ +0 close(3) = 0
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH net 2/2] selftests/net: packetdrill: cover RST validation in SYN-RECEIVED
2026-07-17 8:14 ` [PATCH net 2/2] selftests/net: packetdrill: cover RST validation " Yuxiang Yang
@ 2026-07-20 16:48 ` Eric Dumazet
0 siblings, 0 replies; 6+ messages in thread
From: Eric Dumazet @ 2026-07-20 16:48 UTC (permalink / raw)
To: Yuxiang Yang
Cc: netdev, linux-kernel, linux-kselftest, Neal Cardwell,
Kuniyuki Iwashima, David S . Miller, Jakub Kicinski, Paolo Abeni,
Simon Horman, Shuah Khan, Yizhou Zhao, Ao Wang, Xuewei Feng,
Qi Li, Ke Xu, yyxroy22
On Fri, Jul 17, 2026 at 10:15 AM Yuxiang Yang
<yangyx22@mails.tsinghua.edu.cn> wrote:
>
> Add packetdrill coverage for the RFC 9293 reset checks on request
> sockets in SYN-RECEIVED. Verify that an exact RST removes the request,
> a non-exact in-window RST sends a challenge ACK without removing it,
> and an out-of-window RST is silently discarded.
>
> Also cover an RST|ACK with an unacceptable ACK number to ensure RST
> sequence validation runs before ACK-field validation.
>
> Signed-off-by: Yuxiang Yang <yangyx22@mails.tsinghua.edu.cn>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Thanks!
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH net 0/2] tcp: validate RST sequence in SYN-RECEIVED
2026-07-17 8:14 [PATCH net 0/2] tcp: validate RST sequence in SYN-RECEIVED Yuxiang Yang
2026-07-17 8:14 ` [PATCH net 1/2] tcp: challenge ACK for non-exact RST " Yuxiang Yang
2026-07-17 8:14 ` [PATCH net 2/2] selftests/net: packetdrill: cover RST validation " Yuxiang Yang
@ 2026-07-23 15:40 ` patchwork-bot+netdevbpf
2 siblings, 0 replies; 6+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-07-23 15:40 UTC (permalink / raw)
To: Yuxiang Yang
Cc: netdev, linux-kernel, linux-kselftest, edumazet, ncardwell,
kuniyu, davem, kuba, pabeni, horms, shuah, zhaoyz24, wangao,
fengxw06, qli01, xuke, yyxroy22
Hello:
This series was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Fri, 17 Jul 2026 08:14:41 +0000 you wrote:
> The SYN-RECEIVED request-socket path accepts any in-window RST and
> removes the request, even when SEG.SEQ does not exactly match RCV.NXT.
> RFC 9293 requires a challenge ACK for a non-exact in-window RST.
>
> Patch 1 applies the RFC 5961 sequence check to request sockets and shares
> the per-netns challenge ACK quota with the established-socket path.
> Patch 2 adds a compact packetdrill regression test for exact, non-exact,
> RST|ACK, and out-of-window cases.
>
> [...]
Here is the summary with links:
- [net,1/2] tcp: challenge ACK for non-exact RST in SYN-RECEIVED
https://git.kernel.org/netdev/net/c/a28c4fcbf774
- [net,2/2] selftests/net: packetdrill: cover RST validation in SYN-RECEIVED
https://git.kernel.org/netdev/net/c/7bb18355e599
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 6+ messages in thread