Skip to content

Commit ee6a9bc

Browse files
committed
EBML: Improve ElementReader locking
1 parent 9ec6639 commit ee6a9bc

File tree

5 files changed

+295
-90
lines changed

5 files changed

+295
-90
lines changed

lofty/src/ebml/element_reader.rs

Lines changed: 144 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -214,41 +214,49 @@ ebml_master_elements! {
214214
},
215215
}
216216

217+
#[derive(Debug)]
218+
struct MasterElementContext {
219+
element: MasterElement,
220+
remaining_length: VInt,
221+
}
222+
223+
const MAX_DEPTH: u8 = 16;
224+
const ROOT_DEPTH: u8 = 1;
225+
217226
struct ElementReaderContext {
218-
/// Previous master element
219-
previous_master: Option<MasterElement>,
220-
previous_master_length: VInt,
221-
/// Current master element
222-
current_master: Option<MasterElement>,
223-
/// Remaining length of the master element
224-
master_length: VInt,
227+
depth: u8,
228+
masters: Vec<MasterElementContext>,
225229
/// Maximum size in octets of all element IDs
226230
max_id_length: u8,
227231
/// Maximum size in octets of all element data sizes
228232
max_size_length: u8,
229-
/// Whether the reader is locked to the current master element
233+
/// Whether the reader is locked to the master element at `lock_depth`
230234
///
231235
/// This is set with [`ElementReader::lock`], and is used to prevent
232236
/// the reader from reading past the end of the current master element.
233237
locked: bool,
238+
/// The depth at which we are locked to
239+
lock_depth: u8,
240+
lock_len: VInt,
234241
}
235242

236243
impl Default for ElementReaderContext {
237244
fn default() -> Self {
238245
Self {
239-
previous_master: None,
240-
previous_master_length: VInt::ZERO,
241-
current_master: None,
242-
master_length: VInt::ZERO,
246+
depth: 0,
247+
masters: Vec::with_capacity(MAX_DEPTH as usize),
243248
// https://www.rfc-editor.org/rfc/rfc8794.html#name-ebmlmaxidlength-element
244249
max_id_length: 4,
245250
// https://www.rfc-editor.org/rfc/rfc8794.html#name-ebmlmaxsizelength-element
246251
max_size_length: 8,
247252
locked: false,
253+
lock_depth: 0,
254+
lock_len: VInt::ZERO,
248255
}
249256
}
250257
}
251258

259+
#[derive(Debug)]
252260
pub(crate) enum ElementReaderYield {
253261
Master((ElementIdent, VInt)),
254262
Child((ChildElementDescriptor, VInt)),
@@ -268,8 +276,9 @@ impl ElementReaderYield {
268276

269277
pub fn size(&self) -> Option<u64> {
270278
match self {
271-
ElementReaderYield::Master((_, size)) => Some(size.value()),
272-
ElementReaderYield::Child((_, size)) => Some(size.value()),
279+
ElementReaderYield::Master((_, size)) | ElementReaderYield::Child((_, size)) => {
280+
Some(size.value())
281+
},
273282
ElementReaderYield::Unknown(header) => Some(header.size.value()),
274283
_ => None,
275284
}
@@ -286,8 +295,19 @@ where
286295
R: Read,
287296
{
288297
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
298+
if self.ctx.locked {
299+
let lock_len = self.ctx.lock_len.value();
300+
if buf.len() > lock_len as usize {
301+
return Err(std::io::Error::new(
302+
std::io::ErrorKind::UnexpectedEof,
303+
"Cannot read past the end of the current master element",
304+
));
305+
}
306+
}
307+
289308
let ret = self.reader.read(buf)?;
290-
self.ctx.master_length = self.ctx.master_length.saturating_sub(ret as u64);
309+
let len = self.current_master_length();
310+
self.set_current_master_length(len.saturating_sub(ret as u64));
291311
Ok(ret)
292312
}
293313
}
@@ -311,16 +331,64 @@ where
311331
self.ctx.max_size_length = len
312332
}
313333

314-
fn store_previous_master(&mut self) {
315-
self.ctx.previous_master = self.ctx.current_master;
316-
self.ctx.previous_master_length = self.ctx.master_length;
334+
fn current_master(&self) -> Option<MasterElement> {
335+
if self.ctx.depth == 0 {
336+
assert!(self.ctx.masters.is_empty());
337+
return None;
338+
}
339+
340+
Some(self.ctx.masters[(self.ctx.depth - 1) as usize].element)
317341
}
318342

319-
fn goto_next_master(&mut self) -> Result<ElementReaderYield> {
320-
if self.ctx.master_length != 0 {
321-
self.skip(self.ctx.master_length.value())?;
343+
fn current_master_length(&self) -> VInt {
344+
if self.ctx.depth == 0 {
345+
assert!(self.ctx.masters.is_empty());
346+
return VInt::ZERO;
347+
}
348+
349+
self.ctx.masters[(self.ctx.depth - 1) as usize].remaining_length
350+
}
351+
352+
fn set_current_master_length(&mut self, length: VInt) {
353+
if self.ctx.depth == 0 {
354+
assert!(self.ctx.masters.is_empty());
355+
return;
356+
}
357+
358+
if self.ctx.locked {
359+
self.ctx.lock_len = length;
360+
}
361+
362+
self.ctx.masters[(self.ctx.depth - 1) as usize].remaining_length = length;
363+
}
364+
365+
fn push_new_master(&mut self, master: MasterElement, size: VInt) -> Result<()> {
366+
if self.ctx.depth == MAX_DEPTH {
367+
decode_err!(@BAIL Ebml, "Maximum depth reached");
322368
}
323369

370+
// If we are at the root level, we do not increment the depth
371+
// since we are not actually inside a master element.
372+
// For example, we are moving from \EBML to \Segment.
373+
let at_root_level = self.ctx.depth == ROOT_DEPTH && self.current_master_length() == 0;
374+
if at_root_level {
375+
assert_eq!(self.ctx.masters.len(), 1);
376+
self.ctx.masters.clear();
377+
} else {
378+
self.ctx.depth += 1;
379+
}
380+
381+
self.ctx.masters.push(MasterElementContext {
382+
element: master,
383+
remaining_length: size,
384+
});
385+
386+
Ok(())
387+
}
388+
389+
fn goto_next_master(&mut self) -> Result<ElementReaderYield> {
390+
self.exhaust_current_master()?;
391+
324392
let header = ElementHeader::read(
325393
&mut self.reader,
326394
self.ctx.max_id_length,
@@ -331,35 +399,34 @@ where
331399
return Ok(ElementReaderYield::Unknown(header));
332400
};
333401

334-
self.store_previous_master();
335-
self.ctx.current_master = Some(*master);
336-
self.ctx.master_length = header.size;
337-
Ok(ElementReaderYield::Master((
338-
master.id,
339-
self.ctx.master_length,
340-
)))
402+
self.push_new_master(*master, header.size)?;
403+
404+
Ok(ElementReaderYield::Master((master.id, header.size)))
341405
}
342406

343-
pub(crate) fn goto_previous_master(&mut self) -> Result<()> {
344-
if let Some(previous_master) = self.ctx.previous_master {
345-
self.ctx.current_master = Some(previous_master);
346-
self.ctx.master_length = self.ctx.previous_master_length;
347-
Ok(())
348-
} else {
349-
decode_err!(@BAIL Ebml, "Expected a parent element to be available")
407+
fn goto_previous_master(&mut self) -> Result<()> {
408+
if self.ctx.depth == 0 || self.ctx.depth == self.ctx.lock_depth {
409+
decode_err!(@BAIL Ebml, "Cannot go to previous master element, already at root")
350410
}
411+
412+
self.exhaust_current_master()?;
413+
414+
self.ctx.depth -= 1;
415+
let _ = self.ctx.masters.pop();
416+
417+
Ok(())
351418
}
352419

353420
pub(crate) fn next(&mut self) -> Result<ElementReaderYield> {
354-
let Some(current_master) = self.ctx.current_master else {
421+
let Some(current_master) = self.current_master() else {
355422
return self.goto_next_master();
356423
};
357424

358-
if self.ctx.master_length == 0 {
359-
if self.ctx.locked {
360-
return Ok(ElementReaderYield::Eof);
361-
}
425+
if self.ctx.locked && self.ctx.lock_len == 0 {
426+
return Ok(ElementReaderYield::Eof);
427+
}
362428

429+
if self.current_master_length() == 0 {
363430
return self.goto_next_master();
364431
}
365432

@@ -374,13 +441,12 @@ where
374441
};
375442

376443
if child.data_type == ElementDataType::Master {
377-
self.store_previous_master();
378-
self.ctx.current_master = Some(
444+
self.push_new_master(
379445
*master_elements()
380446
.get(&header.id)
381447
.expect("Nested master elements should be defined at this level."),
382-
);
383-
self.ctx.master_length = header.size;
448+
header.size,
449+
)?;
384450

385451
// We encountered a nested master element
386452
return Ok(ElementReaderYield::Master((child.ident, header.size)));
@@ -389,11 +455,22 @@ where
389455
Ok(ElementReaderYield::Child((*child, header.size)))
390456
}
391457

392-
fn lock(&mut self) {
458+
pub(crate) fn exhaust_current_master(&mut self) -> Result<()> {
459+
let master_length = self.current_master_length().value();
460+
if master_length == 0 {
461+
return Ok(());
462+
}
463+
464+
self.skip(master_length)?;
465+
Ok(())
466+
}
467+
468+
pub(crate) fn lock(&mut self) {
393469
self.ctx.locked = true;
470+
self.ctx.lock_len = self.current_master_length();
394471
}
395472

396-
fn unlock(&mut self) {
473+
pub(crate) fn unlock(&mut self) {
397474
self.ctx.locked = false;
398475
}
399476

@@ -403,13 +480,20 @@ where
403480
}
404481

405482
pub(crate) fn skip(&mut self, length: u64) -> Result<()> {
483+
log::trace!("Skipping {} bytes", length);
484+
485+
let current_master_length = self.current_master_length();
486+
if length > current_master_length.value() {
487+
decode_err!(@BAIL Ebml, "Cannot skip past the end of the current master element")
488+
}
489+
406490
std::io::copy(&mut self.by_ref().take(length), &mut std::io::sink())?;
407491
Ok(())
408492
}
409493

410494
pub(crate) fn skip_element(&mut self, element_header: ElementHeader) -> Result<()> {
411495
log::debug!(
412-
"Encountered unknown EBML element in header: {:X}",
496+
"Encountered unknown EBML element: {:X}, skipping",
413497
element_header.id.0
414498
);
415499
self.skip(element_header.size.value())?;
@@ -445,6 +529,16 @@ where
445529
Ok(u64::from_be_bytes(buf))
446530
}
447531

532+
/// Same as `read_unsigned_int`, but will warn if the value is out of range.
533+
pub(crate) fn read_flag(&mut self, element_length: u64) -> Result<bool> {
534+
let val = self.read_unsigned_int(element_length)?;
535+
if val > 1 {
536+
log::warn!("Flag value `{}` is out of range, assuming true", val);
537+
}
538+
539+
Ok(val != 0)
540+
}
541+
448542
pub(crate) fn read_float(&mut self, element_length: u64) -> Result<f64> {
449543
// https://www.rfc-editor.org/rfc/rfc8794.html#section-7.3
450544
// A Float Element MUST declare a length of either zero octets (0 bit),
@@ -513,18 +607,16 @@ where
513607
self.reader.skip_element(header)?;
514608
self.next()
515609
},
516-
Ok(ElementReaderYield::Eof) => Ok(None),
517610
Err(e) => Err(e),
518611
element => element.map(Some),
519612
}
520613
}
521614

522615
pub(crate) fn master_exhausted(&self) -> bool {
523-
self.reader.ctx.master_length == 0
524-
}
616+
let lock_depth = self.reader.ctx.lock_depth;
617+
assert!(lock_depth < self.reader.ctx.depth);
525618

526-
pub(crate) fn inner(&mut self) -> &mut ElementReader<R> {
527-
self.reader
619+
self.reader.ctx.masters[lock_depth as usize].remaining_length == 0
528620
}
529621
}
530622

lofty/src/ebml/read.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,18 +77,29 @@ where
7777
let mut child_reader = element_reader.children();
7878
while let Some(child) = child_reader.next()? {
7979
let ident;
80-
let data_ty;
8180
let size;
8281

8382
match child {
8483
// The only expected master element in the header is `DocTypeExtension`
85-
ElementReaderYield::Master((ElementIdent::DocTypeExtension, _)) => continue,
84+
ElementReaderYield::Master((ElementIdent::DocTypeExtension, size)) => {
85+
child_reader.skip(size.value())?;
86+
continue;
87+
},
88+
ElementReaderYield::Master(_) => {
89+
decode_err!(
90+
@BAIL Ebml,
91+
"Unexpected master element in the EBML header"
92+
);
93+
},
8694
ElementReaderYield::Child((child, size_)) => {
8795
ident = child.ident;
88-
data_ty = child.data_type;
8996
size = size_;
9097
},
91-
_ => break,
98+
ElementReaderYield::Unknown(header) => {
99+
child_reader.skip_element(header)?;
100+
continue;
101+
},
102+
ElementReaderYield::Eof => break,
92103
}
93104

94105
if ident == ElementIdent::EBMLMaxIDLength {

0 commit comments

Comments
 (0)