From: Denis V. Lunev <[email protected]>

bf.granularity comes from the image and is passed to
bdrv_create_dirty_bitmap(), which asserts on it. An otherwise valid
image thus aborts qemu-img for a granularity of zero or one which is
not a power of two. The shift by BDRV_SECTOR_BITS is done on a
uint32_t as well, so 1 << 23 sectors and above wrap to zero and hit
the same assertion.

Compute the granularity in 64 bits and reject what
bdrv_create_dirty_bitmap() cannot accept.

Fixes: baefd977002e ("parallels: support bitmap extension for read-only mode")
Cc: Stefan Hajnoczi <[email protected]>
Cc: Thomas Huth <[email protected]>
Signed-off-by: Denis V. Lunev <[email protected]>
---
 block/parallels-ext.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/block/parallels-ext.c b/block/parallels-ext.c
index baee86a159..830ac78a11 100644
--- a/block/parallels-ext.c
+++ b/block/parallels-ext.c
@@ -31,6 +31,7 @@
 #include "parallels.h"
 #include "crypto/hash.h"
 #include "qemu/bswap.h"
+#include "qemu/host-utils.h"
 #include "qemu/uuid.h"
 #include "qemu/memalign.h"
 
@@ -122,7 +123,7 @@ parallels_load_bitmap(BlockDriverState *bs, uint8_t *data, 
size_t data_size,
     BdrvDirtyBitmap *bitmap;
     QemuUUID uuid;
     char uuidstr[UUID_STR_LEN];
-    uint64_t bm_size, tab_size;
+    uint64_t bm_size, tab_size, granularity;
     int i;
 
     if (data_size < sizeof(bf)) {
@@ -133,7 +134,7 @@ parallels_load_bitmap(BlockDriverState *bs, uint8_t *data, 
size_t data_size,
     }
     memcpy(&bf, data, sizeof(bf));
     bf.size = le64_to_cpu(bf.size);
-    bf.granularity = le32_to_cpu(bf.granularity) << BDRV_SECTOR_BITS;
+    bf.granularity = le32_to_cpu(bf.granularity);
     bf.l1_size = le32_to_cpu(bf.l1_size);
     data += sizeof(bf);
     data_size -= sizeof(bf);
@@ -144,6 +145,16 @@ parallels_load_bitmap(BlockDriverState *bs, uint8_t *data, 
size_t data_size,
         return NULL;
     }
 
+    /* bdrv_create_dirty_bitmap() asserts on an unusable granularity */
+    granularity = (uint64_t)bf.granularity << BDRV_SECTOR_BITS;
+    if (granularity < BDRV_SECTOR_SIZE || granularity > UINT32_MAX ||
+        !is_power_of_2(granularity)) {
+        error_setg(errp, "Invalid bitmap granularity %" PRIu64 ", expected a "
+                   "power of two of at least %" PRIu64 " bytes", granularity,
+                   (uint64_t)BDRV_SECTOR_SIZE);
+        return NULL;
+    }
+
     if (bf.l1_size * sizeof(uint64_t) > data_size) {
         error_setg(errp, "Bitmaps feature corrupted: l1 table exceeds "
                    "extension data_size");
@@ -152,7 +163,7 @@ parallels_load_bitmap(BlockDriverState *bs, uint8_t *data, 
size_t data_size,
 
     memcpy(&uuid, bf.id, sizeof(uuid));
     qemu_uuid_unparse(&uuid, uuidstr);
-    bitmap = bdrv_create_dirty_bitmap(bs, bf.granularity, uuidstr, errp);
+    bitmap = bdrv_create_dirty_bitmap(bs, granularity, uuidstr, errp);
     if (!bitmap) {
         return NULL;
     }
-- 
2.53.0


Reply via email to