diff --git a/src/block.rs b/src/block.rs index 80fcd9c..525dc77 100644 --- a/src/block.rs +++ b/src/block.rs @@ -7,6 +7,8 @@ use std::convert::TryInto; use std::io::{Read, Write}; use std::iter::repeat; +const MAX_METADATA_BLOCK_LEN: u32 = 1 << 24; + // BlockType {{{ /// Types of blocks. Used primarily to map blocks to block identifiers when reading and writing. #[allow(missing_docs)] @@ -132,6 +134,13 @@ impl Block { Block::Unknown((_, ref bytes)) => (bytes.len() as u32, Some(bytes.clone())), }; + if MAX_METADATA_BLOCK_LEN <= content_len { + return Err(Error::new( + ErrorKind::InvalidInput, + "metadata block size exceeds 24-bit length limit (16 MiB)", + )); + } + let mut byte: u8 = 0; if is_last { byte |= 0x80; @@ -1262,3 +1271,22 @@ pub(crate) fn read_ident(mut reader: R) -> Result<()> { )) } } + +#[cfg(test)] +mod tests { + use super::*; + use std::io::Cursor; + + #[test] + fn write_rejects_oversized_metadata_block() { + // Metadata blocks must be less than 16 MiB in size. + let too_big_block = Block::Padding(16 * 1024 * 1024); + let mut writer = Cursor::new(Vec::new()); + let err = too_big_block.write_to(false, &mut writer).unwrap_err(); + assert!(matches!(err.kind, ErrorKind::InvalidInput)); + assert_eq!( + err.description, + "metadata block size exceeds 24-bit length limit (16 MiB)" + ); + } +}