Skip to content

consommé: Don't drop the connection when a stale SYN is received from the guest - #4149

Open
Blue (OneBlue) wants to merge 1 commit into
microsoft:mainfrom
OneBlue:user/oneblue/port-reuse-syn
Open

consommé: Don't drop the connection when a stale SYN is received from the guest#4149
Blue (OneBlue) wants to merge 1 commit into
microsoft:mainfrom
OneBlue:user/oneblue/port-reuse-syn

Conversation

@OneBlue

Copy link
Copy Markdown
Contributor

This change solves an issue where we incorrectly drop a connection if we receive a SYN packet that matches a stale tuple.

Sample repro:

The guest packets are normal TCP reactions during a rapid loopback connection reuse:

15:47:53.516214  recv SYN
127.0.0.1:12974 -> 127.0.0.1:5000

Dockerd sends this SYN to open a new HTTP connection to the local registry for the blob-upload  PATCH .

15:47:53.516216  xmit ACK
15:47:53.516326  recv RST

 net_consomme  still associates the tuple with an older connection and replies with an ACK rather than a SYN-ACK. Because that ACK does not acknowledge the new SYN correctly, the guest TCP stack rejects it with RST.

15:47:53.526396  recv SYN

The guest retransmits the unanswered SYN. DeviceHost then establishes the host-side connection and accepts it through the registry port forward:

15:47:53.526662  connection established
15:47:53.526781  TCP connection established
FourTuple { src: 169.254.73.250:5000,
            dst: 169.254.73.254:12974 }

Consomme sends a new SYN toward the guest registry. The guest responds with an ACK-only packet because that reverse tuple still matches stale guest TCP state, rather than starting a new passive-open handshake with SYN-ACK:

15:47:53.526831  recv tcp packet, control=None
15:47:53.526835  invalid packet waiting for syn, drop connection

Consomme is in  SynSent  and treats the ACK-only response as fatal. It closes the accepted socket, causing:

15:47:53.527042  socket write error, os error 10053
15:47:53.527270  Patch "http://127.0.0.1:5000/v2/...": EOF
15:47:53.528002  WslcPushSessionImage returned 0x80004005

Thus, the guest behavior follows TCP rules; the bug is that consomme drops the new forwarded socket instead of resetting the stale tuple and retrying its SYN.

@OneBlue
Blue (OneBlue) requested a review from a team as a code owner August 3, 2026 21:32
Copilot AI review requested due to automatic review settings August 3, 2026 21:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a TCP port-forward edge case in the consomme user-mode TCP stack: when a new forwarded connection reuses a 4-tuple that the guest still associates with a recently-closed (stale) connection, an ACK-only response from the guest should no longer cause consomme to drop the newly accepted host-side socket. Instead, consomme resets the stale tuple state and retries the SYN to complete the handshake.

Changes:

  • Prevent send_next from emitting data/ACK traffic while the connection is still in SynSent.
  • In SynSent, detect an unacceptable/stale ACK-only response, send a RST to clear stale state, rewind the transmit sequence, and retry the active-open SYN.
  • Add a regression test that reproduces and validates recovery from the stale-ACK-on-reused-tuple scenario.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
vm/devices/net/net_consomme/consomme/src/tcp/tests.rs Adds a regression test covering recovery from a stale guest ACK on a reused tuple during port-forward handshake.
vm/devices/net/net_consomme/consomme/src/tcp.rs Adjusts SynSent behavior to avoid sending data/ACK prematurely and to reset+retry when a stale/unacceptable ACK arrives.

Comment on lines +923 to +924
let connector = std::net::TcpStream::connect(host_addr).unwrap();
connector.set_nonblocking(true).unwrap();
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants