From: Eric Dumazet Date: Mon, 8 Jun 2026 15:14:52 +0000 (+0000) Subject: tcp: refine tcp_sequence() for the FIN exception X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=91934d44468d8d674248c4dfd93a8999e0b4594f;p=thirdparty%2Flinux.git tcp: refine tcp_sequence() for the FIN exception Commit 0e24d17bd966 ("tcp: implement RFC 7323 window retraction receiver requirements") removed the special FIN case that was added in commit 1e3bb184e941 ("tcp: re-enable acceptance of FIN packets when RWIN is 0"). If a peer sends a segment containing data and a FIN flag before it learns about our window retraction and has a buggy TCP stack, it might place the FIN one byte beyond what it thinks is the right edge of the window (i.e., max_window_edge + 1). The data portion (end_seq - th->fin) will end exactly at max_window_edge. In this case, we will drop the packet if our receive queue is not empty, even though the data was sent within the window we previously allowed. Signed-off-by: Eric Dumazet Reviewed-by: Neal Cardwell Reviewed-by: Kuniyuki Iwashima Reviewed-by: Simon Baatz Link: https://patch.msgid.link/20260608151452.706822-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index ab7a4e5435a8..8560a9c6d382 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4812,18 +4812,20 @@ static enum skb_drop_reason tcp_sequence(const struct sock *sk, const struct tcphdr *th) { const struct tcp_sock *tp = tcp_sk(sk); + u32 seq_limit; if (before(end_seq, tp->rcv_wup)) return SKB_DROP_REASON_TCP_OLD_SEQUENCE; - if (unlikely(after(end_seq, tp->rcv_nxt + tcp_max_receive_window(tp)))) { + seq_limit = tp->rcv_nxt + tcp_max_receive_window(tp); + if (unlikely(after(end_seq, seq_limit))) { /* Some stacks are known to handle FIN incorrectly; allow the * FIN to extend beyond the window and check it in detail later. */ - if (!after(end_seq - th->fin, tp->rcv_nxt + tcp_receive_window(tp))) + if (!after(end_seq - th->fin, seq_limit)) return SKB_NOT_DROPPED_YET; - if (after(seq, tp->rcv_nxt + tcp_max_receive_window(tp))) + if (after(seq, seq_limit)) return SKB_DROP_REASON_TCP_INVALID_SEQUENCE; /* Only accept this packet if receive queue is empty. */