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

parallels_parse_format_extension() advances the cursor over the feature
payload but subtracts only the feature header size from the remaining
byte count. A feature whose payload reaches the end of the extension
cluster leaves the cursor at the end of the allocation while the count
still allows one more header, which the next iteration then reads out
of bounds, 0 bytes after the 512 byte cluster. The stale count also
breaks the data_size bound of any further feature, so
parallels_load_bitmap() can read past the cluster as well.

Account the aligned payload in both the cursor and the count. Aligning
data_size before the bound check changes nothing, as the count is
always a multiple of 8, but it has to be computed in 64 bits: on a
uint32_t a data_size of 0xfffffff9 or above wraps to zero.

Reported-by: Martin Holeček
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4156
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 | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/block/parallels-ext.c b/block/parallels-ext.c
index 7f6ab6b0d2..baee86a159 100644
--- a/block/parallels-ext.c
+++ b/block/parallels-ext.c
@@ -239,6 +239,7 @@ parallels_parse_format_extension(BlockDriverState *bs, 
uint8_t *ext_cluster,
     while (true) {
         ParallelsFeatureHeader fh;
         BdrvDirtyBitmap *bitmap;
+        uint64_t data_size;
 
         if (remaining < sizeof(fh)) {
             error_setg(errp, "Can not read feature header, as remaining bytes "
@@ -260,7 +261,8 @@ parallels_parse_format_extension(BlockDriverState *bs, 
uint8_t *ext_cluster,
             goto fail;
         }
 
-        if (fh.data_size > remaining) {
+        data_size = QEMU_ALIGN_UP((uint64_t)fh.data_size, 8);
+        if (data_size > remaining) {
             error_setg(errp, "Feature data_size exceedes Format Extension "
                        "cluster");
             goto fail;
@@ -283,7 +285,8 @@ parallels_parse_format_extension(BlockDriverState *bs, 
uint8_t *ext_cluster,
             goto fail;
         }
 
-        pos = ext_cluster + QEMU_ALIGN_UP(pos + fh.data_size - ext_cluster, 8);
+        pos += data_size;
+        remaining -= data_size;
     }
 
 fail:
-- 
2.53.0


Reply via email to