quic: validate stream limits in transport params
The maximum number of streams of a given type (bidi/uni)
is capped to 2^60, since a larger number would overflow
a varint.
Validate limits received in transport parameters.
RFC 9000, Section 4.6
For golang/go#58547
Change-Id: I7a4a15c569da91ad1b89a5dc71e1c5b213dbda9a
Reviewed-on: https://go-review.googlesource.com/c/net/+/524037
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/internal/quic/packet_parser.go b/internal/quic/packet_parser.go
index 9a00da7..ca5b37b 100644
--- a/internal/quic/packet_parser.go
+++ b/internal/quic/packet_parser.go
@@ -378,7 +378,7 @@
return 0, 0, -1
}
n += nn
- if v > 1<<60 {
+ if v > maxStreamsLimit {
return 0, 0, -1
}
return typ, int64(v), n
diff --git a/internal/quic/quic.go b/internal/quic/quic.go
index 8cd61ae..71738e1 100644
--- a/internal/quic/quic.go
+++ b/internal/quic/quic.go
@@ -55,6 +55,10 @@
// https://www.rfc-editor.org/rfc/rfc9000#section-14.1
const minimumClientInitialDatagramSize = 1200
+// Maximum number of streams of a given type which may be created.
+// https://www.rfc-editor.org/rfc/rfc9000.html#section-4.6-2
+const maxStreamsLimit = 1 << 60
+
// A connSide distinguishes between the client and server sides of a connection.
type connSide int8
diff --git a/internal/quic/stream_test.go b/internal/quic/stream_test.go
index bafd236..7b8ba2c 100644
--- a/internal/quic/stream_test.go
+++ b/internal/quic/stream_test.go
@@ -1165,8 +1165,8 @@
// permissiveTransportParameters may be passed as an option to newTestConn.
func permissiveTransportParameters(p *transportParameters) {
- p.initialMaxStreamsBidi = maxVarint
- p.initialMaxStreamsUni = maxVarint
+ p.initialMaxStreamsBidi = maxStreamsLimit
+ p.initialMaxStreamsUni = maxStreamsLimit
p.initialMaxData = maxVarint
p.initialMaxStreamDataBidiRemote = maxVarint
p.initialMaxStreamDataBidiLocal = maxVarint
diff --git a/internal/quic/transport_params.go b/internal/quic/transport_params.go
index 89ea69f..dc76d16 100644
--- a/internal/quic/transport_params.go
+++ b/internal/quic/transport_params.go
@@ -212,8 +212,14 @@
p.initialMaxStreamDataUni, n = consumeVarintInt64(val)
case paramInitialMaxStreamsBidi:
p.initialMaxStreamsBidi, n = consumeVarintInt64(val)
+ if p.initialMaxStreamsBidi > maxStreamsLimit {
+ return p, localTransportError(errTransportParameter)
+ }
case paramInitialMaxStreamsUni:
p.initialMaxStreamsUni, n = consumeVarintInt64(val)
+ if p.initialMaxStreamsUni > maxStreamsLimit {
+ return p, localTransportError(errTransportParameter)
+ }
case paramAckDelayExponent:
var v uint64
v, n = consumeVarint(val)
diff --git a/internal/quic/transport_params_test.go b/internal/quic/transport_params_test.go
index e1c45ca..cc88e83 100644
--- a/internal/quic/transport_params_test.go
+++ b/internal/quic/transport_params_test.go
@@ -237,6 +237,20 @@
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
},
}, {
+ desc: "initial_max_streams_bidi is too large",
+ enc: []byte{
+ 0x08, // initial_max_streams_bidi,
+ 8, // length,
+ 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ },
+ }, {
+ desc: "initial_max_streams_uni is too large",
+ enc: []byte{
+ 0x08, // initial_max_streams_uni,
+ 9, // length,
+ 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ },
+ }, {
desc: "preferred_address is too short",
enc: []byte{
0x0d, // preferred_address