Merge pull request #2711 from lucas-clemente/validate-quic-config

disallow values above 2^60 for Config.MaxIncoming{Uni}Streams
This commit is contained in:
Marten Seemann 2020-08-18 06:58:55 +07:00 committed by GitHub
commit c978b6050c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 54 additions and 11 deletions

View file

@ -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 {

View file

@ -487,8 +487,8 @@ var _ = Describe("Client", func() {
c := populateClientConfig(config, false)
Expect(c.HandshakeTimeout).To(Equal(1337 * time.Minute))
Expect(c.MaxIdleTimeout).To(Equal(42 * time.Hour))
Expect(c.MaxIncomingStreams).To(Equal(1234))
Expect(c.MaxIncomingUniStreams).To(Equal(4321))
Expect(c.MaxIncomingStreams).To(BeEquivalentTo(1234))
Expect(c.MaxIncomingUniStreams).To(BeEquivalentTo(4321))
Expect(c.ConnectionIDLength).To(Equal(13))
Expect(c.StatelessResetKey).To(Equal([]byte("foobar")))
Expect(c.QuicTracer).To(Equal(tracer))
@ -511,7 +511,7 @@ var _ = Describe("Client", func() {
}
c := populateClientConfig(config, false)
Expect(c.MaxIncomingStreams).To(BeZero())
Expect(c.MaxIncomingUniStreams).To(Equal(4321))
Expect(c.MaxIncomingUniStreams).To(BeEquivalentTo(4321))
})
It("disables unidirectional streams", func() {
@ -520,7 +520,7 @@ var _ = Describe("Client", func() {
MaxIncomingUniStreams: -1,
}
c := populateClientConfig(config, false)
Expect(c.MaxIncomingStreams).To(Equal(1234))
Expect(c.MaxIncomingStreams).To(BeEquivalentTo(1234))
Expect(c.MaxIncomingUniStreams).To(BeZero())
})

View file

@ -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 &copy
}
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 {

View file

@ -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()
@ -45,9 +63,9 @@ var _ = Describe("Config", func() {
case "MaxReceiveConnectionFlowControlWindow":
f.Set(reflect.ValueOf(uint64(10)))
case "MaxIncomingStreams":
f.Set(reflect.ValueOf(11))
f.Set(reflect.ValueOf(int64(11)))
case "MaxIncomingUniStreams":
f.Set(reflect.ValueOf(12))
f.Set(reflect.ValueOf(int64(12)))
case "StatelessResetKey":
f.Set(reflect.ValueOf([]byte{1, 2, 3, 4}))
case "KeepAlive":
@ -114,8 +132,8 @@ var _ = Describe("Config", func() {
Expect(c.HandshakeTimeout).To(Equal(protocol.DefaultHandshakeTimeout))
Expect(c.MaxReceiveStreamFlowControlWindow).To(BeEquivalentTo(protocol.DefaultMaxReceiveStreamFlowControlWindow))
Expect(c.MaxReceiveConnectionFlowControlWindow).To(BeEquivalentTo(protocol.DefaultMaxReceiveConnectionFlowControlWindow))
Expect(c.MaxIncomingStreams).To(Equal(protocol.DefaultMaxIncomingStreams))
Expect(c.MaxIncomingUniStreams).To(Equal(protocol.DefaultMaxIncomingUniStreams))
Expect(c.MaxIncomingStreams).To(BeEquivalentTo(protocol.DefaultMaxIncomingStreams))
Expect(c.MaxIncomingUniStreams).To(BeEquivalentTo(protocol.DefaultMaxIncomingUniStreams))
})
It("populates empty fields with default values, for the server", func() {

View file

@ -242,13 +242,15 @@ 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 int
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 int
MaxIncomingUniStreams int64
// The StatelessResetKey is used to generate stateless reset tokens.
// If no key is configured, sending of stateless resets is disabled.
StatelessResetKey []byte

View file

@ -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) {