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