@@ -24,6 +24,8 @@ use std::io::{Cursor, Read, Write};
24
24
#[ cfg( test) ]
25
25
use proptest:: prelude:: * ;
26
26
27
+ use crate :: protocol:: vec_builder:: DEFAULT_BLOCK_SIZE ;
28
+
27
29
use super :: {
28
30
primitives:: { Int16 , Int32 , Int64 , Int8 , Varint , Varlong } ,
29
31
traits:: { ReadError , ReadType , WriteError , WriteType } ,
@@ -610,16 +612,35 @@ where
610
612
let uncompressed_size = decompress_len ( & input) . unwrap ( ) ;
611
613
612
614
// Decode snappy payload.
613
- let mut decoder = Decoder :: new ( ) ;
614
- let mut output = vec ! [ 0 ; uncompressed_size] ;
615
- let actual_uncompressed_size = decoder
616
- . decompress ( & input, & mut output)
617
- . map_err ( |e| ReadError :: Malformed ( Box :: new ( e) ) ) ?;
618
- if actual_uncompressed_size != uncompressed_size {
619
- return Err ( ReadError :: Malformed (
620
- "broken snappy data" . to_string ( ) . into ( ) ,
621
- ) ) ;
622
- }
615
+ // The uncompressed length is unchecked and can be up to 2^32-1 bytes. To avoid a DDoS vector we try to
616
+ // limit it to a small size and if that fails we double that size;
617
+ let mut max_uncompressed_size = DEFAULT_BLOCK_SIZE ;
618
+ let output = loop {
619
+ let try_uncompressed_size = uncompressed_size. min ( max_uncompressed_size) ;
620
+
621
+ let mut decoder = Decoder :: new ( ) ;
622
+ let mut output = vec ! [ 0 ; try_uncompressed_size] ;
623
+ let actual_uncompressed_size = match decoder. decompress ( & input, & mut output) {
624
+ Ok ( size) => size,
625
+ Err ( snap:: Error :: BufferTooSmall { .. } )
626
+ if max_uncompressed_size < uncompressed_size =>
627
+ {
628
+ // try larger buffer
629
+ max_uncompressed_size *= 2 ;
630
+ continue ;
631
+ }
632
+ Err ( e) => {
633
+ return Err ( ReadError :: Malformed ( Box :: new ( e) ) ) ;
634
+ }
635
+ } ;
636
+ if actual_uncompressed_size != uncompressed_size {
637
+ return Err ( ReadError :: Malformed (
638
+ "broken snappy data" . to_string ( ) . into ( ) ,
639
+ ) ) ;
640
+ }
641
+
642
+ break output;
643
+ } ;
623
644
624
645
// Read uncompressed records.
625
646
let mut decoder = Cursor :: new ( output) ;
0 commit comments