Blob Blame History Raw
From cf4d05bfef24e6e79ef3d6b90815009facf753d8 Mon Sep 17 00:00:00 2001
From: Jeff Cody <jcody@redhat.com>
Date: Wed, 26 Mar 2014 13:05:39 +0100
Subject: [PATCH] vhdx: Bounds checking for block_size and logical_sector_size
 (CVE-2014-0148)

Other variables (e.g. sectors_per_block) are calculated using these
variables, and if not range-checked illegal values could be obtained
causing infinite loops and other potential issues when calculating
BAT entries.

The 1.00 VHDX spec requires BlockSize to be min 1MB, max 256MB.
LogicalSectorSize is required to be either 512 or 4096 bytes.

Reported-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Jeff Cody <jcody@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 1d7678dec4761acdc43439da6ceda41a703ba1a6)
---
 block/vhdx.c | 12 ++++++++++--
 block/vhdx.h |  4 ++++
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/block/vhdx.c b/block/vhdx.c
index e9704b1..36fc06c 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -627,12 +627,20 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
     le32_to_cpus(&s->logical_sector_size);
     le32_to_cpus(&s->physical_sector_size);
 
-    if (s->logical_sector_size == 0 || s->params.block_size == 0) {
+    if (s->params.block_size < VHDX_BLOCK_SIZE_MIN ||
+        s->params.block_size > VHDX_BLOCK_SIZE_MAX) {
         ret = -EINVAL;
         goto exit;
     }
 
-    /* both block_size and sector_size are guaranteed powers of 2 */
+    /* only 2 supported sector sizes */
+    if (s->logical_sector_size != 512 && s->logical_sector_size != 4096) {
+        ret = -EINVAL;
+        goto exit;
+    }
+
+    /* Both block_size and sector_size are guaranteed powers of 2, below.
+       Due to range checks above, s->sectors_per_block can never be < 256 */
     s->sectors_per_block = s->params.block_size / s->logical_sector_size;
     s->chunk_ratio = (VHDX_MAX_SECTORS_PER_BLOCK) *
                      (uint64_t)s->logical_sector_size /
diff --git a/block/vhdx.h b/block/vhdx.h
index fb687ed..227ac99 100644
--- a/block/vhdx.h
+++ b/block/vhdx.h
@@ -280,6 +280,10 @@ typedef struct QEMU_PACKED VHDXPage83Data {
                                            support page 0x83 */
 } VHDXPage83Data;
 
+#define KiB                             (1 * 1024)
+#define MiB                             (KiB * 1024)
+#define VHDX_BLOCK_SIZE_MIN             (1   * MiB)
+#define VHDX_BLOCK_SIZE_MAX             (256 * MiB)
 typedef struct QEMU_PACKED VHDXVirtualDiskLogicalSectorSize {
     uint32_t    logical_sector_size;    /* virtual disk sector size (in bytes).
                                            Can only be 512 or 4096 bytes */