Fix thread safety in SafeEvpPKeyHandle.DuplicateHandle#124485
Fix thread safety in SafeEvpPKeyHandle.DuplicateHandle#124485
Conversation
Use DangerousAddRef/DangerousRelease to prevent the source handle from being disposed by another thread while DuplicateHandle reads the handle value. Capture handle and ExtraHandle values into local variables while the ref count is elevated, so a concurrent Dispose cannot zero them out before they are copied to the new SafeEvpPKeyHandle. Co-authored-by: vcsjones <361677+vcsjones@users.noreply.github.com>
...s/System.Security.Cryptography/src/System/Security/Cryptography/SafeEvpPKeyHandle.OpenSsl.cs
Outdated
Show resolved
Hide resolved
...s/System.Security.Cryptography/src/System/Security/Cryptography/SafeEvpPKeyHandle.OpenSsl.cs
Show resolved
Hide resolved
...s/System.Security.Cryptography/src/System/Security/Cryptography/SafeEvpPKeyHandle.OpenSsl.cs
Show resolved
Hide resolved
…ut catch Co-authored-by: vcsjones <361677+vcsjones@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes a thread-safety race condition in SafeEvpPKeyHandle.DuplicateHandle() where concurrent calls to Dispose() could zero the handle field between the UpRef operation and copying the handle to the new SafeHandle, resulting in an undisposed handle with an invalid IntPtr.Zero value.
Changes:
- Wrap DuplicateHandle operation in DangerousAddRef/DangerousRelease to prevent concurrent Dispose from zeroing handle fields mid-operation
- Add regression test exercising concurrent DuplicateHandle/Dispose calls
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SafeEvpPKeyHandle.OpenSsl.cs |
Added DangerousAddRef/DangerousRelease protection around UpRefEvpPkey and handle copy operations in DuplicateHandle method |
src/libraries/System.Security.Cryptography.OpenSsl/tests/SafeEvpPKeyHandleTests.cs |
Added test that runs 1000 iterations of concurrent DuplicateHandle/Dispose to verify the race condition is fixed |
src/libraries/System.Security.Cryptography.OpenSsl/tests/SafeEvpPKeyHandleTests.cs
Show resolved
Hide resolved
src/libraries/System.Security.Cryptography.OpenSsl/tests/SafeEvpPKeyHandleTests.cs
Outdated
Show resolved
Hide resolved
…t formatting Co-authored-by: vcsjones <361677+vcsjones@users.noreply.github.com>
|
|
||
| // Capture handle and ExtraHandle before UpRefEvpPkey so that a concurrent | ||
| // Dispose cannot zero the fields between UpRef and the copy below. | ||
| IntPtr currentHandle = handle; |
There was a problem hiding this comment.
@copilot Please revert this file to the previous commit. It turns out we want to keep the add ref / release approach. The test changes are fine.
There was a problem hiding this comment.
Reverted to the DangerousAddRef/DangerousRelease approach from bffea02. All 1867 tests pass. Fixed in 5c810a4.
Co-authored-by: vcsjones <361677+vcsjones@users.noreply.github.com>
Co-authored-by: vcsjones <361677+vcsjones@users.noreply.github.com>
|
@copilot please invoke the code-review skill and post the results as a comment on this PR. |
🤖 Copilot Code ReviewHolistic AssessmentMotivation: The race condition is real and well-demonstrated by the reproduction in the issue. Between Approach: Wrapping the critical section in Summary: Detailed Findings✅ Core fix —
|
...s/System.Security.Cryptography/src/System/Security/Cryptography/SafeEvpPKeyHandle.OpenSsl.cs
Outdated
Show resolved
Hide resolved
|
Tagging subscribers to this area: @bartonjs, @vcsjones, @dotnet/area-system-security |
...s/System.Security.Cryptography/src/System/Security/Cryptography/SafeEvpPKeyHandle.OpenSsl.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: vcsjones <361677+vcsjones@users.noreply.github.com>
SafeEvpPKeyHandle.DuplicateHandleDuplicateHandleusingDangerousAddRef/DangerousReleaseto prevent concurrentDisposefrom zeroing handle fieldsDuplicateHandle/DisposeDangerousAddRef/DangerousReleaseapproachkeyHandle.Dispose()(the dispose thread already handles it)Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.