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

parallels_load_bitmap_data() derives the number of bytes to
deserialize from "bm_size - offset" without checking that the offset
is still inside the bitmap, and an offset past the end makes that
subtraction underflow.

The overflow which used to produce such an offset is fixed by
"dirty-bitmap: fix integer overflow in serialization coverage", but
both the cluster size and the L1 contents come from the image, so
refuse the table explicitly. The check cannot reject a valid table:
l1_size is DIV_ROUND_UP(bm_size, limit), so the largest offset the
loop reaches is (l1_size - 1) * limit, always below bm_size.

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 | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/block/parallels-ext.c b/block/parallels-ext.c
index 830ac78a11..63fe4d5b1e 100644
--- a/block/parallels-ext.c
+++ b/block/parallels-ext.c
@@ -76,8 +76,17 @@ parallels_load_bitmap_data(BlockDriverState *bs, const 
uint64_t *l1_table,
     buf = qemu_blockalign(bs, s->cluster_size);
     limit = bdrv_dirty_bitmap_serialization_coverage(s->cluster_size, bitmap);
     for (i = 0, offset = 0; i < l1_size; ++i, offset += limit) {
-        uint64_t count = MIN(bm_size - offset, limit);
-        uint64_t entry = l1_table[i];
+        uint64_t count, entry;
+
+        if (offset >= bm_size) {
+            error_setg(errp, "Bitmap L1 table covers more than the bitmap "
+                       "size %" PRIu64, bm_size);
+            ret = -EINVAL;
+            goto finish;
+        }
+
+        count = MIN(bm_size - offset, limit);
+        entry = l1_table[i];
 
         if (entry == 0) {
             /* No need to deserialize zeros because @bitmap is cleared. */
-- 
2.53.0


Reply via email to