summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan Reid <dgreid@chromium.org>2019-06-14 11:41:07 -0700
committerCommit Bot <commit-bot@chromium.org>2019-06-21 19:22:33 +0000
commit70d7bad28414e4b0d8bdf2d5eb85618a3b1e83c6 (patch)
tree529536de447e8b5b09fe308b49eb273215e39726
parentc9f254b1921335231b32550b5ae6b8416e1ca7aa (diff)
downloadcrosvm-70d7bad28414e4b0d8bdf2d5eb85618a3b1e83c6.tar
crosvm-70d7bad28414e4b0d8bdf2d5eb85618a3b1e83c6.tar.gz
crosvm-70d7bad28414e4b0d8bdf2d5eb85618a3b1e83c6.tar.bz2
crosvm-70d7bad28414e4b0d8bdf2d5eb85618a3b1e83c6.tar.lz
crosvm-70d7bad28414e4b0d8bdf2d5eb85618a3b1e83c6.tar.xz
crosvm-70d7bad28414e4b0d8bdf2d5eb85618a3b1e83c6.tar.zst
crosvm-70d7bad28414e4b0d8bdf2d5eb85618a3b1e83c6.zip
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>
-rw-r--r--qcow/src/qcow.rs16
1 files changed, 16 insertions, 0 deletions
diff --git a/qcow/src/qcow.rs b/qcow/src/qcow.rs
index 4b781f4..7528773 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);
@@ -1809,6 +1816,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();
         header[24] = 0;