diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Android/SafeDeleteSslContext.cs b/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Android/SafeDeleteSslContext.cs index 0f141c0812f942..a7a4b4a6b52d1b 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Android/SafeDeleteSslContext.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Android/SafeDeleteSslContext.cs @@ -7,6 +7,7 @@ using System.Security.Authentication; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; +using System.Threading; using PAL_KeyAlgorithm = Interop.AndroidCrypto.PAL_KeyAlgorithm; using PAL_SSLStreamStatus = Interop.AndroidCrypto.PAL_SSLStreamStatus; @@ -29,6 +30,8 @@ internal sealed class SafeDeleteSslContext : SafeDeleteContext private readonly SafeSslHandle _sslContext; + private readonly Lock _lock = new Lock(); + private ArrayBuffer _inputBuffer = new ArrayBuffer(InitialBufferSize); private ArrayBuffer _outputBuffer = new ArrayBuffer(InitialBufferSize); @@ -36,6 +39,8 @@ internal sealed class SafeDeleteSslContext : SafeDeleteContext public SafeSslHandle SslContext => _sslContext; + private volatile bool _disposed; + public SafeDeleteSslContext(SslAuthenticationOptions authOptions) : base(IntPtr.Zero) { @@ -59,13 +64,21 @@ public SafeDeleteSslContext(SslAuthenticationOptions authOptions) protected override void Dispose(bool disposing) { - if (disposing) + lock (_lock) { - if (_sslContext is SafeSslHandle sslContext) + if (!_disposed) { - _inputBuffer.Dispose(); - _outputBuffer.Dispose(); - sslContext.Dispose(); + _disposed = true; + + // First dispose the SSL context to trigger native cleanup + _sslContext.Dispose(); + + if (disposing) + { + // Then dispose the buffers + _inputBuffer.Dispose(); + _outputBuffer.Dispose(); + } } } @@ -78,11 +91,19 @@ private static unsafe void WriteToConnection(IntPtr connection, byte* data, int SafeDeleteSslContext? context = (SafeDeleteSslContext?)GCHandle.FromIntPtr(connection).Target; Debug.Assert(context != null); - var inputBuffer = new ReadOnlySpan(data, dataLength); + lock (context._lock) + { + if (context._disposed) + { + return; + } + + var inputBuffer = new ReadOnlySpan(data, dataLength); - context._outputBuffer.EnsureAvailableSpace(dataLength); - inputBuffer.CopyTo(context._outputBuffer.AvailableSpan); - context._outputBuffer.Commit(dataLength); + context._outputBuffer.EnsureAvailableSpace(dataLength); + inputBuffer.CopyTo(context._outputBuffer.AvailableSpan); + context._outputBuffer.Commit(dataLength); + } } [UnmanagedCallersOnly] @@ -91,45 +112,60 @@ private static unsafe PAL_SSLStreamStatus ReadFromConnection(IntPtr connection, SafeDeleteSslContext? context = (SafeDeleteSslContext?)GCHandle.FromIntPtr(connection).Target; Debug.Assert(context != null); - int toRead = *dataLength; - if (toRead == 0) - return PAL_SSLStreamStatus.OK; - - if (context._inputBuffer.ActiveLength == 0) + lock (context._lock) { - *dataLength = 0; - return PAL_SSLStreamStatus.NeedData; - } + if (context._disposed) + { + *dataLength = 0; + return PAL_SSLStreamStatus.Error; + } - toRead = Math.Min(toRead, context._inputBuffer.ActiveLength); + int toRead = *dataLength; + if (toRead == 0) + return PAL_SSLStreamStatus.OK; - context._inputBuffer.ActiveSpan.Slice(0, toRead).CopyTo(new Span(data, toRead)); - context._inputBuffer.Discard(toRead); + if (context._inputBuffer.ActiveLength == 0) + { + *dataLength = 0; + return PAL_SSLStreamStatus.NeedData; + } + + toRead = Math.Min(toRead, context._inputBuffer.ActiveLength); + + context._inputBuffer.ActiveSpan.Slice(0, toRead).CopyTo(new Span(data, toRead)); + context._inputBuffer.Discard(toRead); - *dataLength = toRead; - return PAL_SSLStreamStatus.OK; + *dataLength = toRead; + return PAL_SSLStreamStatus.OK; + } } internal void Write(ReadOnlySpan buf) { - _inputBuffer.EnsureAvailableSpace(buf.Length); - buf.CopyTo(_inputBuffer.AvailableSpan); - _inputBuffer.Commit(buf.Length); + lock (_lock) + { + _inputBuffer.EnsureAvailableSpace(buf.Length); + buf.CopyTo(_inputBuffer.AvailableSpan); + _inputBuffer.Commit(buf.Length); + } } internal int BytesReadyForConnection => _outputBuffer.ActiveLength; internal void ReadPendingWrites(ref ProtocolToken token) { - if (_outputBuffer.ActiveLength == 0) + lock (_lock) { - token.Size = 0; - token.Payload = null; - return; - } + if (_outputBuffer.ActiveLength == 0) + { + token.Size = 0; + token.Payload = null; + return; + } - token.SetPayload(_outputBuffer.ActiveSpan); - _outputBuffer.Discard(_outputBuffer.ActiveLength); + token.SetPayload(_outputBuffer.ActiveSpan); + _outputBuffer.Discard(_outputBuffer.ActiveLength); + } } internal int ReadPendingWrites(byte[] buf, int offset, int count) @@ -139,12 +175,15 @@ internal int ReadPendingWrites(byte[] buf, int offset, int count) Debug.Assert(count >= 0); Debug.Assert(count <= buf.Length - offset); - int limit = Math.Min(count, _outputBuffer.ActiveLength); + lock (_lock) + { + int limit = Math.Min(count, _outputBuffer.ActiveLength); - _outputBuffer.ActiveSpan.Slice(0, limit).CopyTo(new Span(buf, offset, limit)); - _outputBuffer.Discard(limit); + _outputBuffer.ActiveSpan.Slice(0, limit).CopyTo(new Span(buf, offset, limit)); + _outputBuffer.Discard(limit); - return limit; + return limit; + } } private static SafeSslHandle CreateSslContext(SslStream.JavaProxy sslStreamProxy, SslAuthenticationOptions authOptions) diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index c52212e3a18e48..c0ac3c43dd3ec9 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -440,7 +440,7 @@ - +