From 70d7bad28414e4b0d8bdf2d5eb85618a3b1e83c6 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Fri, 14 Jun 2019 11:41:07 -0700 Subject: [PATCH] qcow: disallow crazy l1 table sizes Before this change, a corrupt or malicious qcow file could cause crosvm to allocate absurd amounts of memory. The fuzzer found this case, limit the L1 table size so it can't cause issues. BUG=chromium:974123 TEST=run fuzzer locally, add unit test Change-Id: Ieb6db6c87f71df726b3cc9a98404581fe32fb1ce Signed-off-by: Dylan Reid Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1660890 Reviewed-by: Daniel Verkamp Tested-by: kokoro --- qcow/src/qcow.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/qcow/src/qcow.rs b/qcow/src/qcow.rs index 4b781f499b..7528773c15 100644 --- a/qcow/src/qcow.rs +++ b/qcow/src/qcow.rs @@ -38,6 +38,7 @@ pub enum Error { InvalidClusterSize, InvalidIndex, InvalidL1TableOffset, + InvalidL1TableSize(u32), InvalidMagic, InvalidOffset(u64), InvalidRefcountTableOffset, @@ -83,6 +84,7 @@ impl Display for Error { InvalidClusterSize => write!(f, "invalid cluster size"), InvalidIndex => write!(f, "invalid index"), InvalidL1TableOffset => write!(f, "invalid L1 table offset"), + InvalidL1TableSize(size) => write!(f, "invalid L1 table size {}", size), InvalidMagic => write!(f, "invalid magic"), InvalidOffset(_) => write!(f, "invalid offset"), InvalidRefcountTableOffset => write!(f, "invalid refcount table offset"), @@ -357,6 +359,11 @@ impl QcowFile { return Err(Error::UnsupportedVersion(header.version)); } + // Make sure that the L1 table fits in RAM. + if u64::from(header.l1_size) > MAX_RAM_POINTER_TABLE_SIZE { + return Err(Error::InvalidL1TableSize(header.l1_size)); + } + let cluster_bits: u32 = header.cluster_bits; if cluster_bits < MIN_CLUSTER_BITS || cluster_bits > MAX_CLUSTER_BITS { return Err(Error::InvalidClusterSize); @@ -1808,6 +1815,15 @@ mod tests { }); } + #[test] + fn test_huge_l1_table() { + let mut header = valid_header(); + header[36] = 0x12; + with_basic_file(&header, |disk_file: File| { + QcowFile::from(disk_file).expect_err("Failed to create file."); + }); + } + #[test] fn test_header_1_tb_file_min_cluster() { let mut header = test_huge_header();