@@ -40,6 +40,9 @@ use tree_builder::tag_sets::*;
4040use util:: str:: to_escaped_string;
4141
4242pub use self :: PushFlag :: * ;
43+ use std:: ops:: { Deref , DerefMut } ;
44+ use std:: cmp:: max;
45+ use std:: slice:: Iter ;
4346
4447#[ macro_use] mod tag_sets;
4548
@@ -48,6 +51,69 @@ mod types;
4851
4952include ! ( concat!( env!( "OUT_DIR" ) , "/rules.rs" ) ) ;
5053
54+ #[ derive( Clone ) ]
55+ pub struct LimitedVec < T > {
56+ vec : Vec < T > ,
57+ limit : usize ,
58+ }
59+
60+ impl < T > LimitedVec < T > {
61+ pub fn new ( limit : usize ) -> Self {
62+ LimitedVec {
63+ vec : vec ! [ ] ,
64+ limit : if limit == 0 { 10 } else { limit } ,
65+ }
66+ }
67+
68+ fn lower_bound ( & self ) -> usize {
69+ let len = self . vec . len ( ) ;
70+ // Watch out for overflow!
71+ max ( len, self . limit ) - self . limit
72+ }
73+
74+ pub fn push ( & mut self , other : T ) {
75+ self . vec . push ( other)
76+ }
77+
78+ pub fn remove ( & mut self , pos : usize ) {
79+ let lower_bound = self . lower_bound ( ) ;
80+ self . vec . remove ( pos + lower_bound) ;
81+ }
82+
83+ pub fn truncate ( & mut self , pos : usize ) {
84+ let lower_bound = self . lower_bound ( ) ;
85+ self . vec . truncate ( pos + lower_bound) ;
86+ }
87+
88+ pub fn pop ( & mut self ) -> Option < T > {
89+ self . vec . pop ( )
90+ }
91+
92+ pub fn insert ( & mut self , index : usize , element : T ) {
93+ let lower_bound = self . lower_bound ( ) ;
94+ self . vec . insert ( index + lower_bound, element)
95+ }
96+
97+ fn real_iter ( & self ) -> Iter < T > {
98+ self . vec . iter ( )
99+ }
100+ }
101+
102+ impl < T > Deref for LimitedVec < T > {
103+ type Target = [ T ] ;
104+ fn deref ( & self ) -> & [ T ] {
105+ let bottom = self . lower_bound ( ) ;
106+ & self . vec [ bottom..]
107+ }
108+ }
109+
110+ impl < T > DerefMut for LimitedVec < T > {
111+ fn deref_mut ( & mut self ) -> & mut [ T ] {
112+ let bottom = self . lower_bound ( ) ;
113+ & mut self . vec [ bottom..]
114+ }
115+ }
116+
51117/// Tree builder options, with an impl for Default.
52118#[ derive( Copy , Clone ) ]
53119pub struct TreeBuilderOpts {
@@ -67,6 +133,13 @@ pub struct TreeBuilderOpts {
67133 /// Obsolete, ignored.
68134 pub ignore_missing_rules : bool ,
69135
136+ /// The maximum amount that the parser will process through the list
137+ /// of active formatting elements and the the stack of open elements.
138+ /// This is set to a finite number to prevent denial-of-service security
139+ /// vulnerabilities. 0 is treated as the default (currently 20); any other
140+ /// value is used as-is.
141+ pub max_stack_depth : u8 ,
142+
70143 /// Initial TreeBuilder quirks mode. Default: NoQuirks
71144 pub quirks_mode : QuirksMode ,
72145}
@@ -79,6 +152,7 @@ impl Default for TreeBuilderOpts {
79152 iframe_srcdoc : false ,
80153 drop_doctype : false ,
81154 ignore_missing_rules : false ,
155+ max_stack_depth : 10 ,
82156 quirks_mode : NoQuirks ,
83157 }
84158 }
@@ -112,10 +186,10 @@ pub struct TreeBuilder<Handle, Sink> {
112186 doc_handle : Handle ,
113187
114188 /// Stack of open elements, most recently added at end.
115- open_elems : Vec < Handle > ,
189+ open_elems : LimitedVec < Handle > ,
116190
117191 /// List of active formatting elements.
118- active_formatting : Vec < FormatEntry < Handle > > ,
192+ active_formatting : LimitedVec < FormatEntry < Handle > > ,
119193
120194 //§ the-element-pointers
121195 /// Head element pointer.
@@ -165,8 +239,8 @@ impl<Handle, Sink> TreeBuilder<Handle, Sink>
165239 pending_table_text : vec ! ( ) ,
166240 quirks_mode : opts. quirks_mode ,
167241 doc_handle : doc_handle,
168- open_elems : vec ! ( ) ,
169- active_formatting : vec ! ( ) ,
242+ open_elems : LimitedVec :: new ( opts . max_stack_depth as usize ) ,
243+ active_formatting : LimitedVec :: new ( opts . max_stack_depth as usize ) ,
170244 head_elem : None ,
171245 form_elem : None ,
172246 frameset_ok : true ,
@@ -197,8 +271,8 @@ impl<Handle, Sink> TreeBuilder<Handle, Sink>
197271 pending_table_text : vec ! ( ) ,
198272 quirks_mode : opts. quirks_mode ,
199273 doc_handle : doc_handle,
200- open_elems : vec ! ( ) ,
201- active_formatting : vec ! ( ) ,
274+ open_elems : LimitedVec :: new ( opts . max_stack_depth as usize ) ,
275+ active_formatting : LimitedVec :: new ( opts . max_stack_depth as usize ) ,
202276 head_elem : None ,
203277 form_elem : form_elem,
204278 frameset_ok : true ,
@@ -251,10 +325,10 @@ impl<Handle, Sink> TreeBuilder<Handle, Sink>
251325 /// internal state. This is intended to support garbage-collected DOMs.
252326 pub fn trace_handles ( & self , tracer : & Tracer < Handle =Handle > ) {
253327 tracer. trace_handle ( & self . doc_handle ) ;
254- for e in & self . open_elems {
328+ for e in self . open_elems . real_iter ( ) {
255329 tracer. trace_handle ( e) ;
256330 }
257- for e in & self . active_formatting {
331+ for e in self . active_formatting . real_iter ( ) {
258332 match e {
259333 & Element ( ref h, _) => tracer. trace_handle ( h) ,
260334 _ => ( ) ,
@@ -269,7 +343,7 @@ impl<Handle, Sink> TreeBuilder<Handle, Sink>
269343 fn dump_state ( & self , label : String ) {
270344 println ! ( "dump_state on {}" , label) ;
271345 print ! ( " open_elems:" ) ;
272- for node in self . open_elems . iter ( ) {
346+ for node in self . open_elems . real_iter ( ) {
273347 let name = self . sink . elem_name ( node) ;
274348 match * name. ns {
275349 ns ! ( html) => print ! ( " {}" , name. local) ,
@@ -278,7 +352,7 @@ impl<Handle, Sink> TreeBuilder<Handle, Sink>
278352 }
279353 println ! ( "" ) ;
280354 print ! ( " active_formatting:" ) ;
281- for entry in self . active_formatting . iter ( ) {
355+ for entry in self . active_formatting . real_iter ( ) {
282356 match entry {
283357 & Marker => print ! ( " Marker" ) ,
284358 & Element ( ref h, _) => {
@@ -477,7 +551,7 @@ impl<Handle, Sink> TokenSink
477551 }
478552
479553 fn end ( & mut self ) {
480- for elem in self . open_elems . drain ( .. ) . rev ( ) {
554+ for elem in self . open_elems . into_iter ( ) . rev ( ) {
481555 self . sink . pop ( & elem) ;
482556 }
483557 }
@@ -688,6 +762,11 @@ impl<Handle, Sink> TreeBuilder<Handle, Sink>
688762 }
689763 ) ;
690764
765+ if fmt_elem_stack_index == 0 {
766+ self . sink . parse_error ( Borrowed ( "Tree too complex to parse correctly – returned tree will be inaccurate" ) ) ;
767+ return
768+ }
769+
691770 // 11.
692771 let common_ancestor = self . open_elems [ fmt_elem_stack_index - 1 ] . clone ( ) ;
693772
0 commit comments