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 <dgreid@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1660890
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
(cherry picked from crosvm commit 70d7bad28414e4b0d8bdf2d5eb85618a3b1e83c6)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Dylan Reid 2019-06-14 11:41:07 -07:00 committed by Samuel Ortiz
parent bd612b6e53
commit 4ba1d2274e

View File

@ -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"),
@ -387,6 +389,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);
@ -1832,6 +1839,15 @@ mod tests {
});
}
#[test]
fn test_huge_l1_table() {
let mut header = valid_header_v3();
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();