https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=298560
Bug ID: 298560
Summary: tcp: ACK header prediction can leave ISS validation
enabled and reject valid ACKs
Product: Base System
Version: CURRENT
Hardware: Any
OS: Any
Status: New
Severity: Affects Some People
Priority: ---
Component: kern
Assignee: [email protected]
Reporter: [email protected]
The default freebsd TCP stack can reject a valid ACK and discard its payload
after a sufficiently long transfer whose advancing ACKs use header prediction.
Cause and proposed fix
ACK header prediction updates snd_una and jumps to check_delack, bypassing the
general ACK-processing code that sets TF2_NO_ISS_CHECK. If that flag remains
clear while snd_una advances far enough from iss, sequence comparisons against
iss become ambiguous. A subsequent segment taking the general processing path
can therefore be rejected as a ghost ACK even though it acknowledges current
data.
The attached patch shares the retirement check in a private inline helper,
called immediately after header prediction advances snd_una and at the existing
general ACK-processing location. It preserves main's SEQ_GT threshold and
initial ghost-ACK validation. Once the flag is set, both calls skip the
sequence
comparison. Predicted data processing has no additional check.
Environment
- FreeBSD main at 3968a8759027b9bb225b439e47f077b3f5b1171f.
- GENERIC arm64 kernels built from that same commit, before and after applying
tcp-iss-retirement.patch.
- FreeBSD 16.0-CURRENT arm64 userland, running under QEMU TCG on a
Linux/AArch64
host. TCP processing runs in the native FreeBSD kernel.
- Each test runs in its own VNET jail, explicitly selects the default freebsd
TCP stack, and checks that net.inet.tcp.insecure_ack is zero.
Reproduction
1. Establish a connection with a synthetic tun(4) peer, without window scaling,
timestamps or SACK. Advertise MSS 1460 and a constant 65535-byte window.
2. Confirm that an initial data-bearing ACK for iss is rejected as a ghost ACK.
3. Send and acknowledge 2147614720 bytes (2 GiB + 128 KiB). Verify through TCP
counters that all 1470969 advancing ACKs used header prediction and that no
retransmission occurred.
4. Send an in-sequence segment carrying one byte ('X'), acknowledging the
current send position, with its advertised window reduced to 65534. This
forces general processing.
5. Check application delivery and the change in tcps_rcvghostack.
Observed results on the two kernels built from the same source commit
Unpatched:
received=-1 errno=35 (EWOULDBLOCK) ghost_ack_delta=1
The valid ACK and its payload were discarded.
Patched:
received=1 errno=0 ghost_ack_delta=0
The application received 'X'.
Both runs transmitted and acknowledged the full 2147614720 bytes, recorded
1470969 predicted advancing ACKs and zero retransmissions, and rejected the
initial ghost ACK. The patched kernel also passed a 128 KiB short-transfer
case and a long-transfer control with an early general-path window update.
The standalone reproducer uses ordinary sockets and tun(4), with no kernel
instrumentation or writes to TCP control-block fields. A run is invalid if
any advancing ACK bypasses header prediction or any retransmission occurs.
Keeping the advertised window constant during the long transfer matters:
an early window update can allow the original general path to retire the
ISS check and mask the defect.
Testing limits
The Kyua/packetdrill TCP suites were not run. RACK, BBR and other architectures
were not tested. These results demonstrate incorrect ACK rejection and data
loss; they do not establish a measured timeout/reset or a performance change.
TCP review of the attached patch is requested. The analysis, patch draft and
regression fixture were prepared with Codex assistance; the native kernel
results above were observed in the described environment.
--
You are receiving this mail because:
You are the assignee for the bug.