@@ -24,6 +24,13 @@ const WASM_HEADER: [u8; 8] = [0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00];
2424const WASM_COMPONENT_HEADER : [ u8 ; 8 ] = [ 0x00 , 0x61 , 0x73 , 0x6d , 0x0d , 0x00 , 0x01 , 0x00 ] ;
2525pub type Header = [ u8 ; 8 ] ;
2626
27+ /// Maximum number of sections accepted by `SectionsIterator` before the parser
28+ /// aborts with `WSError::TooManySections`. 4096 is generous for any legitimate
29+ /// module (the wasm-tools spec recommends ~100 typical sections; the Component
30+ /// Model adds a handful more) while bounding worst-case work for adversarial
31+ /// inputs that declare millions of empty sections.
32+ pub const MAX_SECTIONS : usize = 4096 ;
33+
2734/// A section identifier.
2835#[ derive( Debug , Copy , Clone , Eq , PartialEq ) ]
2936#[ repr( u8 ) ]
@@ -452,14 +459,17 @@ impl Module {
452459 Ok ( ModuleStreamReader { reader, header } )
453460 }
454461
455- /// Return an iterator over the sections of a WebAssembly module.
462+ /// Return an iterator over the sections of a WebAssembly module.
456463 ///
457464 /// The module is read in a streaming fashion, and doesn't have to be fully loaded into memory.
465+ /// The iterator caps total emitted sections at [`MAX_SECTIONS`] to prevent
466+ /// adversarial modules from causing unbounded work.
458467 pub fn iterate < T : Read > (
459468 module_stream : ModuleStreamReader < T > ,
460469 ) -> Result < SectionsIterator < T > , WSError > {
461470 Ok ( SectionsIterator {
462471 reader : module_stream. reader ,
472+ count : 0 ,
463473 } )
464474 }
465475}
@@ -470,18 +480,31 @@ pub struct ModuleStreamReader<'t, T: Read> {
470480}
471481
472482/// An iterator over the sections of a WebAssembly module.
483+ ///
484+ /// Yields at most [`MAX_SECTIONS`] sections; the next call after the cap is
485+ /// reached returns `Some(Err(WSError::TooManySections(MAX_SECTIONS)))` and the
486+ /// iterator subsequently terminates.
473487pub struct SectionsIterator < ' t , T : Read > {
474488 reader : & ' t mut T ,
489+ count : usize ,
475490}
476491
477492impl < ' t , T : Read > Iterator for SectionsIterator < ' t , T > {
478493 type Item = Result < Section , WSError > ;
479494
480495 fn next ( & mut self ) -> Option < Self :: Item > {
496+ if self . count >= MAX_SECTIONS {
497+ // Bound iteration so a malformed module declaring millions of
498+ // empty sections cannot loop the parser indefinitely.
499+ return Some ( Err ( WSError :: TooManySections ( MAX_SECTIONS ) ) ) ;
500+ }
481501 match Section :: deserialize ( self . reader ) {
482502 Err ( e) => Some ( Err ( e) ) ,
483503 Ok ( None ) => None ,
484- Ok ( Some ( section) ) => Some ( Ok ( section) ) ,
504+ Ok ( Some ( section) ) => {
505+ self . count += 1 ;
506+ Some ( Ok ( section) )
507+ }
485508 }
486509 }
487510}
@@ -965,6 +988,39 @@ mod tests {
965988 "tampered component must fail verification"
966989 ) ;
967990 }
991+
992+ #[ test]
993+ fn test_sections_iterator_max_sections_cap ( ) {
994+ // Construct a WASM module: header + (MAX_SECTIONS + 1) empty Type sections.
995+ // Each empty section is two bytes: id=1 (Type), len=0.
996+ // The iterator must reject once it has yielded MAX_SECTIONS sections.
997+ let mut bytes = Vec :: with_capacity ( 8 + 2 * ( MAX_SECTIONS + 1 ) ) ;
998+ bytes. extend_from_slice ( & WASM_HEADER ) ;
999+ for _ in 0 ..( MAX_SECTIONS + 1 ) {
1000+ bytes. push ( 0x01 ) ; // SectionId::Type
1001+ bytes. push ( 0x00 ) ; // payload length 0
1002+ }
1003+
1004+ let mut reader = io:: Cursor :: new ( & bytes) ;
1005+ let stream = Module :: init_from_reader ( & mut reader) . expect ( "header parses" ) ;
1006+ let it = Module :: iterate ( stream) . expect ( "iterator constructs" ) ;
1007+
1008+ let mut seen = 0usize ;
1009+ let mut hit_cap = false ;
1010+ for item in it {
1011+ match item {
1012+ Ok ( _) => seen += 1 ,
1013+ Err ( WSError :: TooManySections ( max) ) => {
1014+ assert_eq ! ( max, MAX_SECTIONS ) ;
1015+ hit_cap = true ;
1016+ break ;
1017+ }
1018+ Err ( e) => panic ! ( "unexpected error before cap: {:?}" , e) ,
1019+ }
1020+ }
1021+ assert_eq ! ( seen, MAX_SECTIONS , "should yield exactly MAX_SECTIONS first" ) ;
1022+ assert ! ( hit_cap, "iterator must error with TooManySections after the cap" ) ;
1023+ }
9681024}
9691025
9701026// ============================================================================
0 commit comments