Skip to content

Commit ef5ddf5

Browse files
authored
prevent concurrent access to IO buffers on macOS (#61723)
1 parent f9dfd41 commit ef5ddf5

File tree

1 file changed

+59
-41
lines changed

1 file changed

+59
-41
lines changed

src/libraries/System.Net.Security/src/System/Net/Security/Pal.OSX/SafeDeleteSslContext.cs

Lines changed: 59 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,11 @@ protected override void Dispose(bool disposing)
158158
SafeSslHandle sslContext = _sslContext;
159159
if (null != sslContext)
160160
{
161-
_inputBuffer.Dispose();
162-
_outputBuffer.Dispose();
161+
lock (_sslContext)
162+
{
163+
_inputBuffer.Dispose();
164+
_outputBuffer.Dispose();
165+
}
163166
sslContext.Dispose();
164167
}
165168
}
@@ -178,18 +181,21 @@ private static unsafe int WriteToConnection(IntPtr connection, byte* data, void*
178181
// but if we were to pool the buffers we would have a potential use-after-free issue.
179182
try
180183
{
181-
ulong length = (ulong)*dataLength;
182-
Debug.Assert(length <= int.MaxValue);
184+
lock (context)
185+
{
186+
ulong length = (ulong)*dataLength;
187+
Debug.Assert(length <= int.MaxValue);
183188

184-
int toWrite = (int)length;
185-
var inputBuffer = new ReadOnlySpan<byte>(data, toWrite);
189+
int toWrite = (int)length;
190+
var inputBuffer = new ReadOnlySpan<byte>(data, toWrite);
186191

187-
context._outputBuffer.EnsureAvailableSpace(toWrite);
188-
inputBuffer.CopyTo(context._outputBuffer.AvailableSpan);
189-
context._outputBuffer.Commit(toWrite);
190-
// Since we can enqueue everything, no need to re-assign *dataLength.
192+
context._outputBuffer.EnsureAvailableSpace(toWrite);
193+
inputBuffer.CopyTo(context._outputBuffer.AvailableSpan);
194+
context._outputBuffer.Commit(toWrite);
195+
// Since we can enqueue everything, no need to re-assign *dataLength.
191196

192-
return OSStatus_noErr;
197+
return OSStatus_noErr;
198+
}
193199
}
194200
catch (Exception e)
195201
{
@@ -207,29 +213,32 @@ private static unsafe int ReadFromConnection(IntPtr connection, byte* data, void
207213

208214
try
209215
{
210-
ulong toRead = (ulong)*dataLength;
211-
212-
if (toRead == 0)
216+
lock (context)
213217
{
214-
return OSStatus_noErr;
215-
}
218+
ulong toRead = (ulong)*dataLength;
216219

217-
uint transferred = 0;
220+
if (toRead == 0)
221+
{
222+
return OSStatus_noErr;
223+
}
218224

219-
if (context._inputBuffer.ActiveLength == 0)
220-
{
221-
*dataLength = (void*)0;
222-
return OSStatus_errSSLWouldBlock;
223-
}
225+
uint transferred = 0;
224226

225-
int limit = Math.Min((int)toRead, context._inputBuffer.ActiveLength);
227+
if (context._inputBuffer.ActiveLength == 0)
228+
{
229+
*dataLength = (void*)0;
230+
return OSStatus_errSSLWouldBlock;
231+
}
232+
233+
int limit = Math.Min((int)toRead, context._inputBuffer.ActiveLength);
226234

227-
context._inputBuffer.ActiveSpan.Slice(0, limit).CopyTo(new Span<byte>(data, limit));
228-
context._inputBuffer.Discard(limit);
229-
transferred = (uint)limit;
235+
context._inputBuffer.ActiveSpan.Slice(0, limit).CopyTo(new Span<byte>(data, limit));
236+
context._inputBuffer.Discard(limit);
237+
transferred = (uint)limit;
230238

231-
*dataLength = (void*)transferred;
232-
return OSStatus_noErr;
239+
*dataLength = (void*)transferred;
240+
return OSStatus_noErr;
241+
}
233242
}
234243
catch (Exception e)
235244
{
@@ -241,24 +250,30 @@ private static unsafe int ReadFromConnection(IntPtr connection, byte* data, void
241250

242251
internal void Write(ReadOnlySpan<byte> buf)
243252
{
244-
_inputBuffer.EnsureAvailableSpace(buf.Length);
245-
buf.CopyTo(_inputBuffer.AvailableSpan);
246-
_inputBuffer.Commit(buf.Length);
253+
lock (_sslContext)
254+
{
255+
_inputBuffer.EnsureAvailableSpace(buf.Length);
256+
buf.CopyTo(_inputBuffer.AvailableSpan);
257+
_inputBuffer.Commit(buf.Length);
258+
}
247259
}
248260

249261
internal int BytesReadyForConnection => _outputBuffer.ActiveLength;
250262

251263
internal byte[]? ReadPendingWrites()
252264
{
253-
if (_outputBuffer.ActiveLength == 0)
265+
lock (_sslContext)
254266
{
255-
return null;
256-
}
267+
if (_outputBuffer.ActiveLength == 0)
268+
{
269+
return null;
270+
}
257271

258-
byte[] buffer = _outputBuffer.ActiveSpan.ToArray();
259-
_outputBuffer.Discard(_outputBuffer.ActiveLength);
272+
byte[] buffer = _outputBuffer.ActiveSpan.ToArray();
273+
_outputBuffer.Discard(_outputBuffer.ActiveLength);
260274

261-
return buffer;
275+
return buffer;
276+
}
262277
}
263278

264279
internal int ReadPendingWrites(byte[] buf, int offset, int count)
@@ -268,12 +283,15 @@ internal int ReadPendingWrites(byte[] buf, int offset, int count)
268283
Debug.Assert(count >= 0);
269284
Debug.Assert(count <= buf.Length - offset);
270285

271-
int limit = Math.Min(count, _outputBuffer.ActiveLength);
286+
lock (_sslContext)
287+
{
288+
int limit = Math.Min(count, _outputBuffer.ActiveLength);
272289

273-
_outputBuffer.ActiveSpan.Slice(0, limit).CopyTo(new Span<byte>(buf, offset, limit));
274-
_outputBuffer.Discard(limit);
290+
_outputBuffer.ActiveSpan.Slice(0, limit).CopyTo(new Span<byte>(buf, offset, limit));
291+
_outputBuffer.Discard(limit);
275292

276-
return limit;
293+
return limit;
294+
}
277295
}
278296

279297
private static readonly SslProtocols[] s_orderedSslProtocols = new SslProtocols[5]

0 commit comments

Comments
 (0)