Skip to content

Commit 9eb5680

Browse files
CarnaViirewtgodbe
authored andcommitted
Merged PR 16175: [5.0] Throw on invalid payload length in WebSockets
**Description:** Avoid integer overflow to prevent infinite loop in reading from WebSocket. (also complies better with WebSocket RFC) MSRC 65273 - Prevents DoS attack by sending frames with invalid payload length. **Risk:** Low **Impacted assemblies:** System.Net.WebSockets.dll System.Net.WebSockets.WebSocketProtocol.dll
1 parent 0fb50b0 commit 9eb5680

File tree

4 files changed

+44
-0
lines changed

4 files changed

+44
-0
lines changed

src/libraries/Common/src/System/Net/WebSockets/ManagedWebSocket.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,14 @@ private async ValueTask CloseWithReceiveErrorAndThrowAsync(
10201020
return SR.net_Websockets_ReservedBitsSet;
10211021
}
10221022

1023+
if (header.PayloadLength < 0)
1024+
{
1025+
// as per RFC, if payload length is a 64-bit integer, the most significant bit MUST be 0
1026+
// frame-payload-length-63 = %x0000000000000000-7FFFFFFFFFFFFFFF; 64 bits in length
1027+
resultHeader = default;
1028+
return SR.net_Websockets_InvalidPayloadLength;
1029+
}
1030+
10231031
if (masked)
10241032
{
10251033
if (!_isServer)

src/libraries/Common/tests/System/Net/WebSockets/WebSocketCreateTest.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,36 @@ public async Task ReceiveAsync_InvalidFrameHeader_AbortsAndThrowsException(byte
147147
}
148148
}
149149

150+
[Theory]
151+
[InlineData(new byte[] { 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, false)] // max allowed value
152+
[InlineData(new byte[] { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, true)]
153+
public async Task ReceiveAsync_InvalidPayloadLength_AbortsAndThrowsException(byte[] lenBytes, bool shouldFail)
154+
{
155+
var frame = new byte[11];
156+
frame[0] = 0b1_000_0010; // FIN, RSV, OPCODE
157+
frame[1] = 0b0_1111111; // MASK, PAYLOAD_LEN
158+
Array.Copy(lenBytes, 0, frame, 2, lenBytes.Length); // EXTENDED_PAYLOAD_LEN
159+
frame[10] = (byte)'a';
160+
161+
using var stream = new MemoryStream(frame, writable: true);
162+
using WebSocket websocket = CreateFromStream(stream, false, null, Timeout.InfiniteTimeSpan);
163+
164+
var buffer = new byte[1];
165+
Task<WebSocketReceiveResult> t = websocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
166+
if (shouldFail)
167+
{
168+
var exc = await Assert.ThrowsAsync<WebSocketException>(() => t);
169+
Assert.Equal(WebSocketState.Aborted, websocket.State);
170+
}
171+
else
172+
{
173+
WebSocketReceiveResult result = await t;
174+
Assert.False(result.EndOfMessage);
175+
Assert.Equal(1, result.Count);
176+
Assert.Equal('a', (char)buffer[0]);
177+
}
178+
}
179+
150180
[Fact]
151181
[PlatformSpecific(~TestPlatforms.Browser)] // System.Net.Sockets is not supported on this platform.
152182
[ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]

src/libraries/System.Net.WebSockets.WebSocketProtocol/src/Resources/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,7 @@
111111
<data name="net_Websockets_UnknownOpcode" xml:space="preserve">
112112
<value>The WebSocket received a frame with an unknown opcode: '0x{0}'.</value>
113113
</data>
114+
<data name="net_Websockets_InvalidPayloadLength" xml:space="preserve">
115+
<value>The WebSocket received a frame with an invalid payload length.</value>
116+
</data>
114117
</root>

src/libraries/System.Net.WebSockets/src/Resources/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,7 @@
138138
<data name="NotWriteableStream" xml:space="preserve">
139139
<value>The base stream is not writeable.</value>
140140
</data>
141+
<data name="net_Websockets_InvalidPayloadLength" xml:space="preserve">
142+
<value>The WebSocket received a frame with an invalid payload length.</value>
143+
</data>
141144
</root>

0 commit comments

Comments
 (0)