From 69df425318e053ccb7e4dc4d5fb2c5594c7928c0 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Tue, 11 Aug 2020 10:44:24 +0700 Subject: [PATCH] limit Config.MaxIncoming{Uni}Streams to 2^60 --- client.go | 3 +++ config.go | 19 ++++++++++++++++++- config_test.go | 18 ++++++++++++++++++ interface.go | 2 ++ server.go | 3 +++ 5 files changed, 44 insertions(+), 1 deletion(-) diff --git a/client.go b/client.go index 63db2cdb..e77a788f 100644 --- a/client.go +++ b/client.go @@ -164,6 +164,9 @@ func dialContext( if tlsConf == nil { return nil, errors.New("quic: tls.Config not set") } + if err := validateConfig(config); err != nil { + return nil, err + } config = populateClientConfig(config, createdPacketConn) packetHandlers, err := getMultiplexer().AddConn(pconn, config.ConnectionIDLength, config.StatelessResetKey, config.Tracer) if err != nil { diff --git a/config.go b/config.go index 1790bbb1..a8c308db 100644 --- a/config.go +++ b/config.go @@ -1,6 +1,10 @@ package quic -import "github.com/lucas-clemente/quic-go/internal/protocol" +import ( + "errors" + + "github.com/lucas-clemente/quic-go/internal/protocol" +) // Clone clones a Config func (c *Config) Clone() *Config { @@ -8,6 +12,19 @@ func (c *Config) Clone() *Config { return © } +func validateConfig(config *Config) error { + if config == nil { + return nil + } + if config.MaxIncomingStreams > 1<<60 { + return errors.New("invalid value for Config.MaxIncomingStreams") + } + if config.MaxIncomingUniStreams > 1<<60 { + return errors.New("invalid value for Config.MaxIncomingUniStreams") + } + return nil +} + // populateServerConfig populates fields in the quic.Config with their default values, if none are set // it may be called with nil func populateServerConfig(config *Config) *Config { diff --git a/config_test.go b/config_test.go index d96fcf80..ad9b23c7 100644 --- a/config_test.go +++ b/config_test.go @@ -15,6 +15,24 @@ import ( ) var _ = Describe("Config", func() { + Context("validating", func() { + It("validates a nil config", func() { + Expect(validateConfig(nil)).To(Succeed()) + }) + + It("validates a config with normal values", func() { + Expect(validateConfig(populateServerConfig(&Config{}))).To(Succeed()) + }) + + It("errors on too large values for MaxIncomingStreams", func() { + Expect(validateConfig(&Config{MaxIncomingStreams: 1<<60 + 1})).To(MatchError("invalid value for Config.MaxIncomingStreams")) + }) + + It("errors on too large values for MaxIncomingUniStreams", func() { + Expect(validateConfig(&Config{MaxIncomingUniStreams: 1<<60 + 1})).To(MatchError("invalid value for Config.MaxIncomingUniStreams")) + }) + }) + configWithNonZeroNonFunctionFields := func() *Config { c := &Config{} v := reflect.ValueOf(c).Elem() diff --git a/interface.go b/interface.go index 9229b216..bb825542 100644 --- a/interface.go +++ b/interface.go @@ -242,10 +242,12 @@ type Config struct { // If this value is zero, it will default to 1.5 MB for the server and 15 MB for the client. MaxReceiveConnectionFlowControlWindow uint64 // MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open. + // Values above 2^60 are invalid. // If not set, it will default to 100. // If set to a negative value, it doesn't allow any bidirectional streams. MaxIncomingStreams int64 // MaxIncomingUniStreams is the maximum number of concurrent unidirectional streams that a peer is allowed to open. + // Values above 2^60 are invalid. // If not set, it will default to 100. // If set to a negative value, it doesn't allow any unidirectional streams. MaxIncomingUniStreams int64 diff --git a/server.go b/server.go index c4fa4291..6766f2f4 100644 --- a/server.go +++ b/server.go @@ -171,6 +171,9 @@ func listen(conn net.PacketConn, tlsConf *tls.Config, config *Config, acceptEarl if tlsConf == nil { return nil, errors.New("quic: tls.Config not set") } + if err := validateConfig(config); err != nil { + return nil, err + } config = populateServerConfig(config) for _, v := range config.Versions { if !protocol.IsValidVersion(v) {