framework: guard executor shared state under stateMu - #24
Open
nadahalli wants to merge 1 commit into
Open
Conversation
The background refresh loop (EnsureFreshEnclaves) and getLocalNodeAndCapConfig rewrite nodeID, enclaves and vaultDON.CryptographyThreshold while Execute reads them concurrently. Only donMembers/donF were guarded, by donMu. A torn read of the nodeID string pairs a new pointer with an old length, which is memory-unsafe, not just stale. Renames donMu to stateMu, moves the unguarded fields under it, and routes access through getters/setters. MockMetrics.Emit is guarded too so the test harness is not itself the race. Adds a -race regression test. It fails on main today with a write in getLocalNodeAndCapConfig against a read in Execute. Ported from confidential-compute#419, which cannot merge now that the repo is archived.
nadahalli
marked this pull request as ready for review
July 29, 2026 11:50
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The race
The background refresh loop (EnsureFreshEnclaves) and getLocalNodeAndCapConfig
rewrite shared executor state while Execute reads it concurrently. Only
donMembers/donF were guarded, by donMu.
Left unprotected:
nodeID(string): written in getLocalNodeAndCapConfig, read in Execute'sscoped emitter. A torn string read pairs a new pointer with an old length.
Memory-unsafe, not just stale.
enclaves([]types.Enclave): written by the refresh loop, read by GetEnclaves.vaultDON.CryptographyThreshold: written by the refresh loop, read inGetEncryptedDecryptionShares.
enclaveClientis NOT part of this. It is published once in initLazily underinitializedMutex.
The fix
Renames donMu to stateMu, moves nodeID and enclaves under it, and routes access
through getters/setters. vaultDON.CryptographyThreshold is guarded via
getVaultThreshold/setVaultThreshold; the rest of vaultDON is publish-once at init.
MockMetrics.Emit is guarded so the harness is not itself the race.
Verification
TestExecutor_ConcurrentRefreshAndExecute_NoDataRace: 8 goroutines x 40 iterations
across Execute / EnsureFreshEnclaves / GetEnclaves.
Reverting executor.go to main while keeping the test reproduces it:
Full framework suite green under -race.