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
