Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'tcp-re-enable-acceptance-of-fin-packets-when-rwin-is-0'

Simon Baatz says:

====================
tcp: re-enable acceptance of FIN packets when RWIN is 0

this series restores the ability to accept in‑sequence FIN packets
even when the advertised receive window is zero, and adds a
packetdrill test to guard the behavior.
====================

Link: https://patch.msgid.link/20260224-fix_zero_wnd_fin-v2-0-a16677ea7cea@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+41 -4
+14 -4
net/ipv4/tcp_input.c
··· 4858 4858 */ 4859 4859 4860 4860 static enum skb_drop_reason tcp_sequence(const struct sock *sk, 4861 - u32 seq, u32 end_seq) 4861 + u32 seq, u32 end_seq, 4862 + const struct tcphdr *th) 4862 4863 { 4863 4864 const struct tcp_sock *tp = tcp_sk(sk); 4865 + u32 seq_limit; 4864 4866 4865 4867 if (before(end_seq, tp->rcv_wup)) 4866 4868 return SKB_DROP_REASON_TCP_OLD_SEQUENCE; 4867 4869 4868 - if (after(end_seq, tp->rcv_nxt + tcp_receive_window(tp))) { 4869 - if (after(seq, tp->rcv_nxt + tcp_receive_window(tp))) 4870 + seq_limit = tp->rcv_nxt + tcp_receive_window(tp); 4871 + if (unlikely(after(end_seq, seq_limit))) { 4872 + /* Some stacks are known to handle FIN incorrectly; allow the 4873 + * FIN to extend beyond the window and check it in detail later. 4874 + */ 4875 + if (!after(end_seq - th->fin, seq_limit)) 4876 + return SKB_NOT_DROPPED_YET; 4877 + 4878 + if (after(seq, seq_limit)) 4870 4879 return SKB_DROP_REASON_TCP_INVALID_SEQUENCE; 4871 4880 4872 4881 /* Only accept this packet if receive queue is empty. */ ··· 6388 6379 6389 6380 step1: 6390 6381 /* Step 1: check sequence number */ 6391 - reason = tcp_sequence(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); 6382 + reason = tcp_sequence(sk, TCP_SKB_CB(skb)->seq, 6383 + TCP_SKB_CB(skb)->end_seq, th); 6392 6384 if (reason) { 6393 6385 /* RFC793, page 37: "In all states except SYN-SENT, all reset 6394 6386 * (RST) segments are validated by checking their SEQ-fields."
+27
tools/testing/selftests/net/packetdrill/tcp_rcv_zero_wnd_fin.pkt
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + // Some TCP stacks send FINs even though the window is closed. We break 4 + // a possible FIN/ACK loop by accepting the FIN. 5 + 6 + --mss=1000 7 + 8 + `./defaults.sh` 9 + 10 + // Establish a connection. 11 + +0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 12 + +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 13 + +0 setsockopt(3, SOL_SOCKET, SO_RCVBUF, [20000], 4) = 0 14 + +0 bind(3, ..., ...) = 0 15 + +0 listen(3, 1) = 0 16 + 17 + +0 < S 0:0(0) win 32792 <mss 1000,nop,wscale 7> 18 + +0 > S. 0:0(0) ack 1 <mss 1460,nop,wscale 0> 19 + +0 < . 1:1(0) ack 1 win 257 20 + 21 + +0 accept(3, ..., ...) = 4 22 + 23 + +0 < P. 1:60001(60000) ack 1 win 257 24 + * > . 1:1(0) ack 60001 win 0 25 + 26 + +0 < F. 60001:60001(0) ack 1 win 257 27 + +0 > . 1:1(0) ack 60002 win 0