From: Jakub Kicinski <kuba@kernel.org>
To: michael.cohen3@mail.huji.ac.il
Cc: Jakub Kicinski <kuba@kernel.org>,
netdev@vger.kernel.org, edumazet@google.com,
ncardwell@google.com, kuniyu@google.com, davem@davemloft.net,
pabeni@redhat.com, horms@kernel.org, tamir.shahar1@gmail.com,
amit.klein@mail.huji.ac.il
Subject: Re: [PATCH net] tcp: reject completely old segments during sequence validation
Date: Thu, 20 Aug 2026 14:25:39 -0700 [thread overview]
Message-ID: <20260820212539.1180651-1-kuba@kernel.org> (raw)
In-Reply-To: <20260818205230.1146138-1-michael.cohen3@mail.huji.ac.il>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
---
tcp: reject completely old segments during sequence validation
tcp_sequence() previously only dropped a segment when end_seq was strictly
before rcv_wup. This patch also drops the boundary case where end_seq
equals rcv_wup, as long as the segment consumes sequence space, so that
such segments no longer reach ACK processing.
> diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> index 0f60a1dbf927..e51c76884460 100644
> --- a/net/ipv4/tcp_input.c
> +++ b/net/ipv4/tcp_input.c
> @@ -4844,7 +4844,8 @@ static enum skb_drop_reason tcp_sequence(const struct sock *sk,
> const struct tcp_sock *tp = tcp_sk(sk);
> u32 seq_limit;
>
> - if (before(end_seq, tp->rcv_wup))
> + if (before(end_seq, tp->rcv_wup) ||
> + (end_seq == tp->rcv_wup && seq != end_seq))
> return SKB_DROP_REASON_TCP_OLD_SEQUENCE;
[Severity: High]
Does this new clause also match the crossing SYN+ACK of a simultaneous
connect(), and does that re-introduce the behaviour fixed by commit
23e89e8ee7be7 ("tcp: Don't drop SYN+ACK for simultaneous connect.")?
When a TCP_SYN_SENT socket receives a bare SYN, the crossed-SYN branch in
tcp_rcv_synsent_state_process() moves it to TCP_SYN_RECV and leaves
rcv_wup equal to rcv_nxt:
net/ipv4/tcp_input.c:tcp_rcv_synsent_state_process() {
...
tcp_set_state(sk, TCP_SYN_RECV);
...
WRITE_ONCE(tp->rcv_nxt, TCP_SKB_CB(skb)->seq + 1);
WRITE_ONCE(tp->copied_seq, tp->rcv_nxt);
tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
...
}
The following tcp_send_synack() sends a segment with TCPHDR_SYN set, and
__tcp_transmit_skb() only calls tcp_select_window() when TCPHDR_SYN is
clear, so rcv_wup is not advanced:
net/ipv4/tcp_output.c:__tcp_transmit_skb() {
...
if (likely(!(tcb->tcp_flags & TCPHDR_SYN))) {
th->window = htons(tcp_select_window(sk));
...
}
The peer's bare SYN+ACK then arrives with end_seq == seq + 1, i.e.
end_seq == tp->rcv_nxt == tp->rcv_wup and seq != end_seq, which is exactly
what the new condition rejects with SKB_DROP_REASON_TCP_OLD_SEQUENCE.
Since th->syn is set, step 1 in tcp_validate_incoming() short-circuits
before step 4:
net/ipv4/tcp_input.c:tcp_validate_incoming() {
...
if (reason) {
if (!th->rst) {
if (th->syn)
goto syn_challenge;
...
}
Is the simultaneous-connect exception in step 4 still reachable after this
change? It requires seq + 1 == end_seq and seq + 1 == tp->rcv_nxt, which
is the same condition the new step 1 check now filters out first:
net/ipv4/tcp_input.c:tcp_validate_incoming() {
...
if (sk->sk_state == TCP_SYN_RECV && sk->sk_socket && th->ack &&
TCP_SKB_CB(skb)->seq + 1 == TCP_SKB_CB(skb)->end_seq &&
TCP_SKB_CB(skb)->seq + 1 == tp->rcv_nxt &&
TCP_SKB_CB(skb)->ack_seq == tp->snd_nxt)
goto pass;
...
}
With that path taken, tcp_rcv_state_process() returns before tcp_ack() and
before the TCP_SYN_RECV to TCP_ESTABLISHED transition, so the visible
effects look like the ones described in 23e89e8ee7be7: a challenge ACK is
emitted instead, TCP_MIB_INERRS and LINUX_MIB_TCPSYNCHALLENGE are
incremented, establishment is delayed by an extra round trip until the
peer's pure ACK (seq == end_seq) is accepted, write() or send() right after
connect() returns -EAGAIN, and bpf_skops_parse_hdr() is not run for the
SYN+ACK. Connect-to-self over loopback follows the same path.
Would restricting the new check so it does not apply while the socket is in
TCP_SYN_RECV with rcv_wup == rcv_nxt, or ordering it after the step 4
simultaneous-connect exception, preserve that case?
Cross-instance finding from sashiko-gemini (9561356177ca94322be4fdd8e89990a9b84fa51eecb45d5907ec165c8b9ca68e):
[Severity: Medium]
The patch breaks IPv6 flowlabel rehashing (ECMP repathing) on spurious RTO for non-SACK connections or when DSACK is disabled.
next prev parent reply other threads:[~2026-08-20 21:25 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-18 20:52 [PATCH net] tcp: reject completely old segments during sequence validation Michael Cohen
2026-08-20 21:25 ` Jakub Kicinski [this message]
2026-08-20 21:26 ` Jakub Kicinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260820212539.1180651-1-kuba@kernel.org \
--to=kuba@kernel.org \
--cc=amit.klein@mail.huji.ac.il \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuniyu@google.com \
--cc=michael.cohen3@mail.huji.ac.il \
--cc=ncardwell@google.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=tamir.shahar1@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox