Fix ConnectAsync sending stale ReceiveAsync buffer via ConnectEx#124381
Fix ConnectAsync sending stale ReceiveAsync buffer via ConnectEx#124381rzikm merged 1 commit intodotnet:mainfrom
Conversation
ConnectAsync(EndPoint) reuses the cached _singleBufferReceiveEventArgs (AwaitableSocketAsyncEventArgs), which may still hold _buffer/_count from a prior ReceiveAsync call. StartOperationConnect does not clear these fields, so DoOperationConnectEx passes the stale buffer to ConnectEx's lpSendBuffer/dwSendDataLength — causing ConnectEx to send stale receive data with the new TCP connection. This is particularly problematic after DisconnectAsync(reuseSocket: true), where the reused socket's second connection silently sends the data received during the first connection, corrupting any protocol handshake (e.g. TLS ClientHello is preceded by the previous connection's data). The fix clears the buffer via SetBuffer(default) before ConnectAsync, ensuring ConnectEx is called with a NULL send buffer (no send-on-connect). Fix dotnet#124353
|
Tagging subscribers to this area: @karelz, @dotnet/ncl |
There was a problem hiding this comment.
Pull request overview
This pull request fixes a critical bug where Socket.ConnectAsync(EndPoint) would inadvertently send stale data from a previous ReceiveAsync operation as "send-on-connect" data with the new TCP connection. This occurred because the cached AwaitableSocketAsyncEventArgs retained buffer state (_buffer, _offset, _count) from prior operations, which ConnectEx interprets as data to send with the connection.
The issue was particularly problematic after DisconnectAsync(reuseSocket: true), where the reused socket's second connection would silently transmit data received during the first connection, potentially corrupting protocol handshakes like TLS ClientHello.
Changes:
- Added
SetBuffer(default)call inConnectAsync(EndPoint, CancellationToken)to clear stale buffer state before connecting - Added comprehensive regression test
DisconnectAndReuse_SameHost_Succeedsthat validates no stale data leaks across connections
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs | Clears cached SAEA buffer state with SetBuffer(default) before ConnectAsync to prevent stale data from being passed to ConnectEx |
| src/libraries/System.Net.Sockets/tests/FunctionalTests/DisconnectTest.cs | Adds regression test that verifies no stale receive data is sent after disconnect+reconnect |
…net#124381) ## Summary `Socket.ConnectAsync(EndPoint)` reuses the cached `_singleBufferReceiveEventArgs` (`AwaitableSocketAsyncEventArgs`), which may still hold `_buffer`/`_count` from a prior `ReceiveAsync` call. `StartOperationConnect` does not clear these fields, so `DoOperationConnectEx` passes the stale buffer to `ConnectEx`'s `lpSendBuffer`/`dwSendDataLength` — causing `ConnectEx` to send stale receive data as "send-on-connect" data with the new TCP connection. This is particularly problematic after `DisconnectAsync(reuseSocket: true)`, where the reused socket's second connection silently sends data received during the first connection, corrupting any protocol handshake (e.g. TLS `ClientHello` is preceded by the previous connection's data). ## Fix Clear the buffer via `SetBuffer(default)` before calling `ConnectAsync` on the cached SAEA, ensuring `ConnectEx` is called with a `NULL` send buffer (no send-on-connect data). ## Reproduction 1. Create a TCP socket, connect, receive data, then `DisconnectAsync(reuseSocket: true)` 2. `ConnectAsync` to the same or different endpoint 3. The server receives stale data from the first connection before any data the client explicitly sends This was verified with: - A .NET loopback test (server receives 65536 leaked bytes = `ReceiveBufferSize`) - A pure C reproduction proving the Windows kernel is correct — `ConnectEx(NULL, 0)` sends nothing; the bug is .NET passing stale buffer/count - Wireshark captures showing stale TLS records from connection 1 being sent on connection 2 Fix dotnet#124353
Summary
Socket.ConnectAsync(EndPoint)reuses the cached_singleBufferReceiveEventArgs(AwaitableSocketAsyncEventArgs), which may still hold_buffer/_countfrom a priorReceiveAsynccall.StartOperationConnectdoes not clear these fields, soDoOperationConnectExpasses the stale buffer toConnectEx'slpSendBuffer/dwSendDataLength— causingConnectExto send stale receive data as "send-on-connect" data with the new TCP connection.This is particularly problematic after
DisconnectAsync(reuseSocket: true), where the reused socket's second connection silently sends data received during the first connection, corrupting any protocol handshake (e.g. TLSClientHellois preceded by the previous connection's data).Fix
Clear the buffer via
SetBuffer(default)before callingConnectAsyncon the cached SAEA, ensuringConnectExis called with aNULLsend buffer (no send-on-connect data).Reproduction
DisconnectAsync(reuseSocket: true)ConnectAsyncto the same or different endpointThis was verified with:
ReceiveBufferSize)ConnectEx(NULL, 0)sends nothing; the bug is .NET passing stale buffer/countFix #124353