AzureAD / azure-activedirectory-identitymodel-extensions-for-dotnet

IdentityModel extensions for .Net
MIT License
1.06k stars 401 forks source link

[Bug] Race condition on ConfigurationManager._syncAfter #2900

Open bruno-brant opened 1 month ago

bruno-brant commented 1 month ago

Which version of Microsoft.IdentityModel are you using? Microsoft.IdentityModel 8.1.2

Where is the issue?

Description

Every calling thread to ConfigurationManager.GetConfigurationAsync will result in a read to _syncAfter to check if a sync should be started; later, a background thread will update _syncAfter with the new sync time. syncAfter is a DateTimeOffset, a struct, so writes to it aren't atomic, so there's a possibility that the calling thread will read corrupt data.

Possible solution

Additional context / logs / screenshots / links to code

jennyf19 commented 1 month ago

FYI @brentschmaltz

brentschmaltz commented 1 month ago

I like the idea to use Epoch time as a long.

bruno-brant commented 1 month ago

I like the idea to use Epoch time as a long.

Longs can still cause an issue in 32-bit architectures unless we use Interlocked or any other synchronization strategy. A int32 is always atomic.

Given the use case, maybe an int32 would suffice? I know the max time shouldn't larger than an int.MaxValue, not sure if the subtraction is cheaper than an interlocked though.

keegan-caruso commented 1 month ago

@brentschmaltz We don't need to store the epoch time, just the offset, which should always be capturable in an int. I think this is the point @bruno-brant is trying to make.

brentschmaltz commented 1 month ago

@keegan-caruso that makes sense also, hadn't thought about 32bit architectures, that is a good point and should be considered.