Skip to content

[release/10.0] Guard against empty remote address on macOS accept - #133567

Merged
wfurt merged 3 commits into
release/10.0from
backport/pr-131869-to-release/10.0
Sep 21, 2026
Merged

wfurt merged 3 commits into
release/10.0from
backport/pr-131869-to-release/10.0

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Backport of #131869 to release/10.0

/cc @wfurt

Customer Impact

In some cases on Apple platforms, an unexpected error can leave us in a permanently broken state — the listening socket remains bound to its port, but the server stops accepting new connections.

This is a small reliability fix for a regression introduced in .NET 10. It was reported by 7 users (GitHub and on the internet).
The fix handles this condition gracefully.

Regression

  • Yes - introduced in .NET 10

Testing

A new test was also added to cover this scenario.
The fix was verified by a customer using a build from the main branch

Risk

Low. This just checks for error and swallows the exception.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@wfurt wfurt added this to the 10.0.x milestone Sep 10, 2026
@wfurt wfurt self-assigned this Sep 10, 2026
@wfurt wfurt added Servicing-consider Issue for next servicing release review area-System.Net.Sockets and removed area-System.Net.Sockets labels Sep 10, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @karelz, @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

@ViveliDuCh

Copy link
Copy Markdown
Member

Hi,

the code complete date for 10.0.13 (the October 2026 release) is Monday 14 September. Make sure to merge this PR on that date at the latest, or it won't make it into that release.

As a reminder, if this is a product change, you also need Tactics approval before merging this PR (test-only or infra-only changes don't require Tactics approval).

@karelz

karelz commented Sep 14, 2026 •

Copy link
Copy Markdown
Member

Team approval - .NET 10 regression - permanently broken state.

wfurt and others added 3 commits September 17, 2026 11:24
Fixes #121848

## Problem

On macOS, when a peer connects to an `AF_INET6` listening socket and
immediately resets the connection (`SO_LINGER=0`), `accept(2)` returns a
valid file descriptor but leaves the remote sockaddr buffer untouched
and reports `addrlen=0`. This kernel behavior was measured with a plain
C repro in the [issue
comment](#121848 (comment))
and does not depend on dual-mode or `IPV6_V6ONLY`.

The 2024 fix (#108616) guarded the `EndPoint.Create` call inside
`FinishOperationAccept` on the Unix path, but the shared
`FinishOperationSyncSuccess` in
[`SocketAsyncEventArgs.cs`](https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs#L1016)
calls `Create` a second time on the same zero-sized `SocketAddress` and
throws `ArgumentException`. For Kestrel this kills the accept loop
permanently while the process stays alive and the port stays bound.

---------

Co-authored-by: Copilot <[email protected]>
…indows/Linux (refs #133778) (#133925)

Workflow artifact: ci-fix
Artifact kind: help
Linked KBE: #133778

> [!NOTE]
> This is an AI/Copilot-generated **best-effort** fix attempt that I
could not fully validate. It is a starting point for a maintainer, not a
finished change. Please review the analysis below before merging.

## Root cause (best analysis)


`System.Net.Sockets.Tests.AcceptDualStackResetTests.Accept_DualStackListener_PeerImmediatelyResets_ListenerStaysHealthy(useAsync:
True)` fails on `windows-x64`/`linux-x64` (`TestReadyToRun_Libraries`
and the runtime pipeline):

```
System.Net.Sockets.SocketException : An existing connection was forcibly closed by the remote host.
   at System.Net.Sockets.Tests.AcceptDualStackResetTests.Accept_DualStackListener_PeerImmediatelyResets_ListenerStaysHealthy(Boolean useAsync) in /_/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs:line 527
```

Line 527 is the `AcceptAsync`/`Accept` call, **not** the receive. The
test (added by #131869) closes an IPv4 peer with
`SO_LINGER=0` so the kernel sends an immediate RST, then expects the
listener to still deliver the healthy IPv6 peer's byte. The `try { ... }
catch (SocketException)` block only wraps the `ReceiveAsync`; the
`accept` that precedes it sits **outside** the `try`. On Windows and
Linux the reset is surfaced by `accept` itself (`WSAECONNRESET` /
"connection forcibly closed"), which escapes the catch and fails the
test, even though the very next accept iteration would return the
healthy peer. macOS discards the reset at accept (which
#131869 hardened `EndPoint.Create` for), so it doesn't hit
this path — which is why the test passed there but not on Windows/Linux.

The test comment already anticipates this ("Some platforms surface the
reset connection from accept()"), but the code doesn't guard the accept
accordingly.

## Attempted fix

Move the `accept` inside the existing `try` block so a `SocketException`
from either the accept or the following receive is tolerated, and the
loop retries to accept the healthy peer on the next iteration (the loop
already runs up to 2 accepts). No production code changes; the
listener-stays-healthy assertion is preserved. This is **not** a
test-disable — the test still runs and still asserts the healthy peer's
message is received.

## What is unverified / where I need help

- I could not build and run `System.Net.Sockets.Tests` in this
environment, so I have not confirmed the test now passes on
windows-x64/linux-x64 while still catching a genuine listener
regression.
- Please confirm the intended contract: on Windows/Linux, should the RST
be observable at `accept` (making tolerating it here correct), or should
the runtime itself suppress the reset connection from the accept loop
the way macOS does? If the latter, the real fix belongs in the socket
accept path rather than the test.

## Validation
- Command: `not run because the sockets functional test suite could not
be built/executed within the run budget`
- Result: not run

## Evidence
- Failing build:
https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1593787
- First build it occurred: after #131869 (merged
2026-09-09, commit 7c35b7d), which introduced this test (computed
within the scanned window; may not be the true origin)
- Suspected regressing change: #131869 (added the test
with the accept outside the catch)

## Help wanted
- Likely author: `@wfurt` (authored #131869 that added the
test)
- Area owners (`area-System.Net.Sockets`): `@dotnet/ncl`

---
Filed by
[`ci-failure-fix`](https://github.com/dotnet/runtime/blob/main/.github/workflows/ci-failure-fix.md).
Comment here or on the workflow file to suggest changes;
[`ci-failure-scan-feedback`](https://github.com/dotnet/runtime/blob/main/.github/workflows/ci-failure-scan-feedback.md)
reads in-scope feedback daily and opens (or updates) a PR with prompt
edits.

Structured data:
```json
{
  "artifact_kind": "help",
  "linked_kbe": 133778,
  "workflow_artifact": "ci-fix"
}
```

> Generated by [CI Outer-Loop Failure
Fixer](https://github.com/dotnet/runtime/actions/runs/34916254170) ·
opus48 · 764.8 AIC · ⌖ 20.8 AIC · ⊞ 19.6K ·
[◷](https://github.com/search?q=repo%3Adotnet%2Fruntime+%22gh-aw-workflow-id%3A+ci-failure-fix%22&type=pullrequests)

<!-- gh-aw-agentic-workflow: CI Outer-Loop Failure Fixer, engine:
copilot, model: claude-opus-4.8, id: 34916254170, workflow_id:
ci-failure-fix, run:
https://github.com/dotnet/runtime/actions/runs/34916254170 -->

<!-- gh-aw-workflow-id: ci-failure-fix -->
<!-- gh-aw-workflow-call-id: dotnet/runtime/ci-failure-fix -->

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <[email protected]>
Use a release-compatible conditional property because the servicing branch's xUnit extensions do not define TestPlatforms.OpenBSD.

Co-authored-by: Copilot <[email protected]>

Copilot-Session: 7ec5412f-9a88-4e9f-a1c4-fcff00d61248
@wfurt

wfurt commented Sep 18, 2026

Copy link
Copy Markdown
Member

approved via email

@rbhanda rbhanda modified the milestones: 10.0.x, 10.0.13 Sep 19, 2026
@wfurt

wfurt commented Sep 21, 2026

Copy link
Copy Markdown
Member

/ba-g test failures unrelated

@wfurt
wfurt merged commit 5e9f5ef into release/10.0 Sep 21, 2026
94 of 100 checks passed
@wfurt
wfurt deleted the backport/pr-131869-to-release/10.0 branch September 21, 2026 17:12
WilliamSmithEdward added a commit to WilliamSmithEdward/embedio-neo that referenced this pull request Oct 13, 2026
.NET 10.0.13 (13 October 2026) is a security release with 44 CVEs,
including CVE-2026-105016, a remote code execution vulnerability in
Microsoft QUIC that MSRC rates Critical for .NET installed on Windows.
Runtime 10.0.13 bundles msquic.dll 2.5.11; 10.0.12 bundled 2.5.10. The
one-week cooldown is skipped for this release.

global.json and the workflows' dotnet-version pins move to SDK 10.0.402.
The MAUI workload set stays at 10.0.401, a set of the 10.0.400 feature
band, so the MAUI apps keep the 10.0.12 Mono runtime. Workload set 10.0.402
carries 10.0.13 but moves the Apple packs to the Xcode 27.0 release; that
move is a separate change.

The shipped dependency minimums move from 10.0.12 to 10.0.13:
System.Threading.RateLimiting (core), System.Text.Json (core .NET Standard
2.0 asset), and Microsoft.Extensions.DependencyInjection and
Microsoft.Extensions.Hosting.Abstractions (DI package). Every lock file is
regenerated with SDK 10.0.402. Each resolved version change is 10.0.12 to
10.0.13, including the implicit Microsoft.NET.ILLink.Tasks and ILCompiler
references; the dependency-free HttpsCertificates lock also moves from
format version 1 to 2. The MAUI locks need the workload to regenerate, so
they mirror the same two entries with the hashes NuGet recorded in the core
lock. coverlet.MTP's Microsoft.Extensions.Configuration dependencies stay
at the 10.0.12 it requests.

The test probes that pin an exact runtime (RuntimeCloseProbe,
AppContainerSmoke and the native dependency probe template) move to
10.0.13, so they exercise the runtime the repository now builds with.

The docs record what the release contains. The macOS accept fix for
dotnet/runtime#121848 (backport dotnet/runtime#133567) ships in
10.0.13; EmbedIO keeps its IPv6 accept worker. The System.Net.Quic
send-buffer fix (dotnet/runtime#135591) is not in 10.0.13. CONTRIBUTING,
SECURITY, the MAUI validation guide and the changelog describe the new
pins.
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 22, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-System.Net.Sockets Servicing-approved Approved for servicing release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants