From 1eef3a8899badf30b4badb65e9d5d2ec9241c0f3 Mon Sep 17 00:00:00 2001 From: RishabhSaini Date: Wed, 6 Jul 2022 18:02:52 -0400 Subject: [PATCH] iso9660.rs: added an error check Added an "Incomplete download of ISO image" error check to the ISO9660 parser and a following test to verify it. --- docs/release-notes.md | 1 + src/iso9660.rs | 31 +++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/docs/release-notes.md b/docs/release-notes.md index adf80e0b9..cc886b137 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -12,6 +12,7 @@ Major changes: Minor changes: - Add release notes to documentation +- Added an error check for detecting an incomplete ISO image Internal changes: diff --git a/src/iso9660.rs b/src/iso9660.rs index 7b82fcf1e..0a30a3daf 100644 --- a/src/iso9660.rs +++ b/src/iso9660.rs @@ -48,8 +48,17 @@ pub struct IsoFs { impl IsoFs { pub fn from_file(mut file: fs::File) -> Result { + let length = file.metadata()?.len(); let descriptors = get_volume_descriptors(&mut file)?; - Ok(Self { descriptors, file }) + let iso_fs = IsoFs { descriptors, file }; + let primary_volume_descriptor = iso_fs.get_primary_volume_descriptor()?; + if u64::from(primary_volume_descriptor.volume_space_size) * ISO9660_SECTOR_SIZE as u64 + > length + { + bail!("Incomplete download of the ISO Image"); + } + + Ok(iso_fs) } pub fn as_file(&mut self) -> Result<&mut fs::File> { @@ -181,6 +190,7 @@ struct BootVolumeDescriptor { struct PrimaryVolumeDescriptor { system_id: String, volume_id: String, + volume_space_size: u32, root: Directory, } @@ -298,13 +308,16 @@ impl PrimaryVolumeDescriptor { parse_iso9660_string(eat(buf, 1), 32, IsoString::StrA).context("parsing system id")?; let volume_id = // technically should be StrD, but non-compliance is common parse_iso9660_string(buf, 32, IsoString::StrA).context("parsing volume id")?; - let root = match get_next_directory_record(eat(buf, 156 - 72), 34, true)? { + eat(buf, 8); // Unused field always 0x00 + let volume_space_size = buf.get_u32_le(); + let root = match get_next_directory_record(eat(buf, 156 - 84), 34, true)? { Some(DirectoryRecord::Directory(d)) => d, _ => bail!("failed to parse root directory record from primary descriptor"), }; Ok(Self { system_id, volume_id, + volume_space_size, root, }) } @@ -554,6 +567,7 @@ fn path_components(s: &str) -> Vec<&str> { mod tests { use super::*; + use anyhow::Error; use std::io::copy; use tempfile::tempfile; @@ -567,8 +581,21 @@ mod tests { IsoFs::from_file(iso_file).unwrap() } + fn open_truncated_iso() -> Result { + let iso_bytes: &[u8] = include_bytes!("../fixtures/iso/synthetic.iso.xz"); + let mut decoder = XzDecoder::new(iso_bytes); + let mut iso_file = tempfile().unwrap(); + copy(&mut decoder, &mut iso_file).unwrap(); + let _output = iso_file.set_len(iso_file.metadata().unwrap().len() / 2); + IsoFs::from_file(iso_file) + } + #[test] fn test_primary_volume_descriptor() { + assert_eq!( + open_truncated_iso().unwrap_err().to_string(), + "Incomplete download of the ISO Image" + ); let iso = open_iso(); let desc = iso.get_primary_volume_descriptor().unwrap(); assert_eq!(desc.system_id, "system-ID-string");