diff --git a/quinn-proto/src/connection.rs b/quinn-proto/src/connection.rs index c15033ee2..c644dfa45 100644 --- a/quinn-proto/src/connection.rs +++ b/quinn-proto/src/connection.rs @@ -946,9 +946,8 @@ impl Connection { } else { SpaceId::Handshake }; - if space < expected - && crypto.offset + crypto.data.len() as u64 > self.space(space).crypto_stream.offset() - { + let end = crypto.offset + crypto.data.len() as u64; + if space < expected && end > self.space(space).crypto_stream.offset() { warn!( self.log, "received new {actual:?} CRYPTO data when expecting {expected:?}", @@ -961,6 +960,10 @@ impl Connection { } let space = &mut self.spaces[space as usize]; + let max = space.crypto_stream.offset() + self.config.crypto_buffer_size as u64; + if end > max { + return Err(TransportError::CRYPTO_BUFFER_EXCEEDED("")); + } space .crypto_stream .insert(crypto.offset, crypto.data.clone()); diff --git a/quinn-proto/src/shared.rs b/quinn-proto/src/shared.rs index 1205e896f..7e925771c 100644 --- a/quinn-proto/src/shared.rs +++ b/quinn-proto/src/shared.rs @@ -105,6 +105,8 @@ pub struct TransportConfig { /// enabled for the connection to be preserved. Must be set lower than the idle_timeout of both /// peers to be effective. pub keep_alive_interval: u32, + /// Maximum quantity of out-of-order crypto layer data to buffer + pub crypto_buffer_size: usize, } impl Default for TransportConfig { @@ -139,6 +141,7 @@ impl Default for TransportConfig { loss_reduction_factor: 0x8000, // 1/2 persistent_congestion_threshold: 3, keep_alive_interval: 0, + crypto_buffer_size: 16 * 1024, } } } @@ -157,6 +160,11 @@ impl TransportConfig { { return Err(ConfigError::VarIntBounds(name)); } + if self.crypto_buffer_size < 4096 { + return Err(ConfigError::IllegalValue( + "crypto_buffer_size must be at least 4096", + )); + } if self.idle_timeout != 0 && u64::from(self.keep_alive_interval) >= self.idle_timeout { warn!( log, diff --git a/quinn-proto/src/transport_error.rs b/quinn-proto/src/transport_error.rs index 9e4a9b89b..ea4f3ce30 100644 --- a/quinn-proto/src/transport_error.rs +++ b/quinn-proto/src/transport_error.rs @@ -163,4 +163,5 @@ errors! { VERSION_NEGOTIATION_ERROR(0x9) "received transport parameters that contained version negotiation parameters that disagreed with the version negotiation that was performed, constituting a potential version downgrade attack"; PROTOCOL_VIOLATION(0xA) "detected an error with protocol compliance that was not covered by more specific error codes"; INVALID_MIGRATION(0xC) "migrated to a different address when the endpoint had disabled migration"; + CRYPTO_BUFFER_EXCEEDED(0xD) "received more data in CRYPTO frames than can be buffered"; }