SIGN IN SIGN UP

xds: fix certificate provider closure race during concurrent TLS handshakes (#9248)

Fixes https://github.com/grpc/grpc-go/issues/9015

Root cause for the race:
- As part of handling configuration updates, the `clusterimpl` LB policy
calls `Close` on its cached certificate providers. The `type` of these
certificate providers, as returned by the provider store, is
`singleCloseWrappedProvider`, which contains a pointer to a reference
counted provider of type `wrappedProvider`.
- `singleCloseWrappedProvider.Close()` mutates the internal pointer to
an instance of `closedProvider` that always returns an error when asked
for key material.
- Any concurrent transport creation for a subchannel that had loaded the
previous `HandshakeInfo` snapshot and was executing a call to
`KeyMaterial` as part of `ClientHandshake` would end up calling
`closedProvider.KeyMaterial`, causing the TLS handshake to fail with:
`provider instance is closed`.
- While `HandshakeInfo` was accessed via an `atomic.Pointer` inside
`clusterimpl` and across the load balancer and transport boundaries, the
fact that `clusterimpl` was retaining mutable references to state inside
the `HandshakeInfo` allowed it to mutate internal in a way that lead to
data races.
  
Changes made here:
- `HandshakeInfo` now owns the lifetime of the provider instances within
it.
- It provides APIs to retrieve the `tls.Config` and internally tracks
the number of active handshakes
- The certificate providers are only closed after the `HandshakeInfo` is
closed and all active handshakes have completed.
- `clusterimpl` keeps track of the most recent security configuration
and suppresses creation of new certificate providers if the config does
not change

RELEASE NOTES:
- xds: Fixed a bug that caused transient handshake failures when TLS
handshakes and xDS Cluster updates happened concurrently.
E
Easwar Swaminathan committed
a620350f3eb2090b518063377c7ad859f252e611
Parent: cc23455
Committed by GitHub <noreply@github.com> on 8/3/2026, 8:04:20 PM