@@ -33,6 +33,9 @@ use std::default::Default;
33
33
use std:: mem:: replace;
34
34
use std:: borrow:: Cow :: Borrowed ;
35
35
use std:: collections:: VecDeque ;
36
+ use std:: ops:: { Deref , DerefMut } ;
37
+ use std:: cmp:: max;
38
+ use std:: slice:: Iter ;
36
39
37
40
#[ macro_use] mod tag_sets;
38
41
@@ -46,6 +49,69 @@ mod rules {
46
49
include ! ( concat!( env!( "OUT_DIR" ) , "/rules.rs" ) ) ;
47
50
}
48
51
52
+ #[ derive( Clone ) ]
53
+ pub struct LimitedVec < T > {
54
+ vec : Vec < T > ,
55
+ limit : usize ,
56
+ }
57
+
58
+ impl < T > LimitedVec < T > {
59
+ pub fn new ( limit : usize ) -> Self {
60
+ LimitedVec {
61
+ vec : vec ! [ ] ,
62
+ limit : if limit == 0 { 10 } else { limit } ,
63
+ }
64
+ }
65
+
66
+ fn lower_bound ( & self ) -> usize {
67
+ let len = self . vec . len ( ) ;
68
+ // Watch out for overflow!
69
+ max ( len, self . limit ) - self . limit
70
+ }
71
+
72
+ pub fn push ( & mut self , other : T ) {
73
+ self . vec . push ( other)
74
+ }
75
+
76
+ pub fn remove ( & mut self , pos : usize ) {
77
+ let lower_bound = self . lower_bound ( ) ;
78
+ self . vec . remove ( pos + lower_bound) ;
79
+ }
80
+
81
+ pub fn truncate ( & mut self , pos : usize ) {
82
+ let lower_bound = self . lower_bound ( ) ;
83
+ self . vec . truncate ( pos + lower_bound) ;
84
+ }
85
+
86
+ pub fn pop ( & mut self ) -> Option < T > {
87
+ self . vec . pop ( )
88
+ }
89
+
90
+ pub fn insert ( & mut self , index : usize , element : T ) {
91
+ let lower_bound = self . lower_bound ( ) ;
92
+ self . vec . insert ( index + lower_bound, element)
93
+ }
94
+
95
+ fn real_iter ( & self ) -> Iter < T > {
96
+ self . vec . iter ( )
97
+ }
98
+ }
99
+
100
+ impl < T > Deref for LimitedVec < T > {
101
+ type Target = [ T ] ;
102
+ fn deref ( & self ) -> & [ T ] {
103
+ let bottom = self . lower_bound ( ) ;
104
+ & self . vec [ bottom..]
105
+ }
106
+ }
107
+
108
+ impl < T > DerefMut for LimitedVec < T > {
109
+ fn deref_mut ( & mut self ) -> & mut [ T ] {
110
+ let bottom = self . lower_bound ( ) ;
111
+ & mut self . vec [ bottom..]
112
+ }
113
+ }
114
+
49
115
/// Tree builder options, with an impl for Default.
50
116
#[ derive( Copy , Clone ) ]
51
117
pub struct TreeBuilderOpts {
@@ -65,6 +131,13 @@ pub struct TreeBuilderOpts {
65
131
/// Obsolete, ignored.
66
132
pub ignore_missing_rules : bool ,
67
133
134
+ /// The maximum amount that the parser will process through the list
135
+ /// of active formatting elements and the the stack of open elements.
136
+ /// This is set to a finite number to prevent denial-of-service security
137
+ /// vulnerabilities. 0 is treated as the default (currently 10); any other
138
+ /// value is used as-is.
139
+ pub max_stack_depth : u8 ,
140
+
68
141
/// Initial TreeBuilder quirks mode. Default: NoQuirks
69
142
pub quirks_mode : QuirksMode ,
70
143
}
@@ -77,6 +150,7 @@ impl Default for TreeBuilderOpts {
77
150
iframe_srcdoc : false ,
78
151
drop_doctype : false ,
79
152
ignore_missing_rules : false ,
153
+ max_stack_depth : 10 ,
80
154
quirks_mode : NoQuirks ,
81
155
}
82
156
}
@@ -110,10 +184,10 @@ pub struct TreeBuilder<Handle, Sink> {
110
184
doc_handle : Handle ,
111
185
112
186
/// Stack of open elements, most recently added at end.
113
- open_elems : Vec < Handle > ,
187
+ open_elems : LimitedVec < Handle > ,
114
188
115
189
/// List of active formatting elements.
116
- active_formatting : Vec < FormatEntry < Handle > > ,
190
+ active_formatting : LimitedVec < FormatEntry < Handle > > ,
117
191
118
192
//§ the-element-pointers
119
193
/// Head element pointer.
@@ -163,8 +237,8 @@ impl<Handle, Sink> TreeBuilder<Handle, Sink>
163
237
pending_table_text : vec ! ( ) ,
164
238
quirks_mode : opts. quirks_mode ,
165
239
doc_handle : doc_handle,
166
- open_elems : vec ! ( ) ,
167
- active_formatting : vec ! ( ) ,
240
+ open_elems : LimitedVec :: new ( opts . max_stack_depth as usize ) ,
241
+ active_formatting : LimitedVec :: new ( opts . max_stack_depth as usize ) ,
168
242
head_elem : None ,
169
243
form_elem : None ,
170
244
frameset_ok : true ,
@@ -195,8 +269,8 @@ impl<Handle, Sink> TreeBuilder<Handle, Sink>
195
269
pending_table_text : vec ! ( ) ,
196
270
quirks_mode : opts. quirks_mode ,
197
271
doc_handle : doc_handle,
198
- open_elems : vec ! ( ) ,
199
- active_formatting : vec ! ( ) ,
272
+ open_elems : LimitedVec :: new ( opts . max_stack_depth as usize ) ,
273
+ active_formatting : LimitedVec :: new ( opts . max_stack_depth as usize ) ,
200
274
head_elem : None ,
201
275
form_elem : form_elem,
202
276
frameset_ok : true ,
@@ -249,10 +323,10 @@ impl<Handle, Sink> TreeBuilder<Handle, Sink>
249
323
/// internal state. This is intended to support garbage-collected DOMs.
250
324
pub fn trace_handles ( & self , tracer : & Tracer < Handle =Handle > ) {
251
325
tracer. trace_handle ( & self . doc_handle ) ;
252
- for e in & self . open_elems {
326
+ for e in self . open_elems . real_iter ( ) {
253
327
tracer. trace_handle ( e) ;
254
328
}
255
- for e in & self . active_formatting {
329
+ for e in self . active_formatting . real_iter ( ) {
256
330
match e {
257
331
& Element ( ref h, _) => tracer. trace_handle ( h) ,
258
332
_ => ( ) ,
@@ -475,7 +549,7 @@ impl<Handle, Sink> TokenSink
475
549
}
476
550
477
551
fn end ( & mut self ) {
478
- for elem in self . open_elems . drain ( .. ) . rev ( ) {
552
+ for elem in self . open_elems . into_iter ( ) . rev ( ) {
479
553
self . sink . pop ( & elem) ;
480
554
}
481
555
}
0 commit comments