From 7d6bf75138bc659f7018997c8abb8f39fe70a4fc Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Fri, 28 Jun 2019 15:19:57 +1000 Subject: [PATCH] qcow: limit the size of a qcow file There are many corner cases when handling sizes that approach u64::max. Limit the files to 16TB. BUG=979458 TEST=Added unittest to check large disks fail Signed-off-by: Dylan Reid Change-Id: I93a87c17267ae69102f8d46ced9dbea8c686d093 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1679892 Reviewed-by: Daniel Verkamp Tested-by: kokoro (cherry picked from crosvm commit 93b0c02227f3acf2c6ff127976875cf3ce98c003) Signed-off-by: Rob Bradford --- qcow/src/qcow.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/qcow/src/qcow.rs b/qcow/src/qcow.rs index b7dbe633b..2fafcd0f3 100755 --- a/qcow/src/qcow.rs +++ b/qcow/src/qcow.rs @@ -77,7 +77,11 @@ impl Display for Error { BackingFilesNotSupported => write!(f, "backing files not supported"), CompressedBlocksNotSupported => write!(f, "compressed blocks not supported"), EvictingCache(e) => write!(f, "failed to evict cache: {}", e), - FileTooBig(size) => write!(f, "file larger than max of 1TB: {}", size), + FileTooBig(size) => write!( + f, + "file larger than max of {}: {}", + MAX_QCOW_FILE_SIZE, size + ), GettingFileSize(e) => write!(f, "failed to get file size: {}", e), GettingRefcount(e) => write!(f, "failed to get refcount: {}", e), InvalidClusterIndex => write!(f, "invalid cluster index"), @@ -118,6 +122,9 @@ pub enum ImageType { Qcow2, } +// Maximum data size supported. +const MAX_QCOW_FILE_SIZE: u64 = 0x01 << 44; // 16 TB. + // QCOW magic constant that starts the header. const QCOW_MAGIC: u32 = 0x5146_49fb; // Default to a cluster size of 2^DEFAULT_CLUSTER_BITS @@ -400,6 +407,11 @@ impl QcowFile { } let cluster_size = 0x01u64 << cluster_bits; + // Limit the total size of the disk. + if header.size > MAX_QCOW_FILE_SIZE { + return Err(Error::FileTooBig(header.size)); + } + // No current support for backing files. if header.backing_file_offset != 0 { return Err(Error::BackingFilesNotSupported); @@ -1839,6 +1851,15 @@ mod tests { }); } + #[test] + fn test_header_crazy_file_size_rejected() { + let mut header = valid_header_v3(); + &mut header[24..32].copy_from_slice(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1e]); + with_basic_file(&header, |disk_file: File| { + QcowFile::from(disk_file).expect_err("Failed to create file."); + }); + } + #[test] fn test_huge_l1_table() { let mut header = valid_header_v3();