[PATCH for-11.0] virtio-blk: fix zone report buffer out-of-memory (CVE-2026-5761)

Stefan Hajnoczi posted 1 patch 1 day, 19 hours ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260409200749.458162-1-stefanha@redhat.com
Maintainers: "Michael S. Tsirkin" <mst@redhat.com>, Stefan Hajnoczi <stefanha@redhat.com>, Kevin Wolf <kwolf@redhat.com>, Hanna Reitz <hreitz@redhat.com>
There is a newer version of this series
hw/block/virtio-blk.c | 100 ++++++++++++++++++++++++++++--------------
1 file changed, 67 insertions(+), 33 deletions(-)
[PATCH for-11.0] virtio-blk: fix zone report buffer out-of-memory (CVE-2026-5761)
Posted by Stefan Hajnoczi 1 day, 19 hours ago
An internal buffer is used when processing VIRTIO_BLK_T_ZONE_REPORT
requests. The buffer's size is controlled by the guest. A large value
can result in g_malloc() failure and the QEMU process aborts, resulting
in a Denial of Service (DoS) (most likely in cases where an untrusted
guest application or a nested guest with virtio-blk passthrough is able
to abort QEMU).

Modify the zone report implementation to work incrementally with a
bounded buffer size.

This is purely a QEMU implementation issue and no VIRTIO spec changes
are needed.

Mingyuan Luo found this bug and provided a reproducer which I haven't
put into tests/qtest/ because it requires a zoned storage device (e.g.
root and modprobe null_blk):

1) Prepare a zoned nullblk backend (/dev/nullb0):

sudo modprobe -r null_blk || true
sudo modprobe null_blk nr_devices=1 zoned=1
sudo chmod 0666 /dev/nullb0
cat /sys/block/nullb0/queue/zoned

2) Create qtest input:

cat >/tmp/vblk-zone-report-oom.qtest <<'EOF'
outl 0xcf8 0x80002004
outw 0xcfc 0x0007
outl 0xcf8 0x80002010
outl 0xcfc 0x0000c001
outb 0xc012 0x00
outb 0xc012 0x01
outb 0xc012 0x03
outl 0xc004 0x00000000
outw 0xc00e 0x0000
outl 0xc008 0x00000100
outb 0xc012 0x07
writel 0x00020000 0x00000010
writel 0x00020004 0x00000000
writeq 0x00020008 0x0000000000000000
writeq 0x00100000 0x0000000000020000
writel 0x00100008 0x00000010
writew 0x0010000c 0x0001
writew 0x0010000e 0x0001
EOF

for i in $(seq 1 1022); do
d=$((0x00100000 + i * 16))
n=$((i + 1))
printf 'writeq 0x%08x 0x0000000000200000\n' "$d" >> /tmp/vblk-zone-report-oom.qtest
printf 'writel 0x%08x 0x1fe00000\n' $((d + 8)) >> /tmp/vblk-zone-report-oom.qtest
printf 'writew 0x%08x 0x0003\n' $((d + 12)) >> /tmp/vblk-zone-report-oom.qtest
printf 'writew 0x%08x 0x%04x\n' $((d + 14)) "$n" >> /tmp/vblk-zone-report-oom.qtest
done

d=$((0x00100000 + 1023 * 16))
printf 'writeq 0x%08x 0x0000000000200000\n' "$d" >> /tmp/vblk-zone-report-oom.qtest
printf 'writel 0x%08x 0x1fe00000\n' $((d + 8)) >> /tmp/vblk-zone-report-oom.qtest
printf 'writew 0x%08x 0x0002\n' $((d + 12)) >> /tmp/vblk-zone-report-oom.qtest
printf 'writew 0x%08x 0x0000\n' $((d + 14)) >> /tmp/vblk-zone-report-oom.qtest
cat >> /tmp/vblk-zone-report-oom.qtest <<'EOF'
writew 0x00104000 0x0000
writew 0x00104002 0x0001
writew 0x00104004 0x0000
outw 0xc010 0x0000
EOF

3) Run the qtest input with ASAN build (compile qemu with --enable-asan):

build/qemu-system-x86_64 -display none \
-accel qtest -qtest stdio \
-machine pc -nodefaults -m 512M -monitor none -serial none \
-blockdev driver=host_device,node-name=disk0,filename=/dev/nullb0 \
-device virtio-blk-pci-transitional,drive=disk0,addr=04.0,queue-size=1024 \
< /tmp/vblk-zone-report-oom.qtest

Cc: Sam Li <faithilikerun@gmail.com>
Cc: Damien Le Moal <dlemoal@kernel.org>
Cc: Dmitry Fomichev <dmitry.fomichev@wdc.com>
Fixes: CVE-2026-5761
Fixes: 4f7366506a9 ("virtio-blk: add zoned storage emulation for zoned devices")
Reported-by: Mingyuan Luo <myluo24@m.fudan.edu.cn>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 hw/block/virtio-blk.c | 100 ++++++++++++++++++++++++++++--------------
 1 file changed, 67 insertions(+), 33 deletions(-)

diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index ddf0e9ee53..7fd883320a 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -38,6 +38,9 @@
 #include "hw/virtio/virtio-blk-common.h"
 #include "qemu/coroutine.h"
 
+/* Internal buffer size limit for zone report */
+#define VIRTIO_BLK_MAX_ZONES_PER_BATCH 4096
+
 static void virtio_blk_ioeventfd_attach(VirtIOBlock *s);
 
 static void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq,
@@ -447,15 +450,22 @@ err:
     return err_status;
 }
 
+typedef struct {
+    unsigned int total_nr_zones;    /* max zones to fill in this request */
+    unsigned int nr_zones_done;     /* how many zones have been filled in */
+    int64_t iov_offset;             /* current byte position in in_iov[] */
+    int64_t offset;                 /* current zone report disk offset */
+    unsigned int nr_zones;          /* for zone report calls */
+    unsigned int zones_per_batch;   /* size of zone report buffer */
+    BlockZoneDescriptor *zones;     /* zone report buffer */
+} ZoneReportData;
+
 typedef struct ZoneCmdData {
     VirtIOBlockReq *req;
     struct iovec *in_iov;
     unsigned in_num;
     union {
-        struct {
-            unsigned int nr_zones;
-            BlockZoneDescriptor *zones;
-        } zone_report_data;
+        ZoneReportData zone_report_data;
         struct {
             int64_t offset;
         } zone_append_data;
@@ -512,16 +522,15 @@ static bool check_zoned_request(VirtIOBlock *s, int64_t offset, int64_t len,
 static void virtio_blk_zone_report_complete(void *opaque, int ret)
 {
     ZoneCmdData *data = opaque;
+    ZoneReportData *zrd = &data->zone_report_data;
     VirtIOBlockReq *req = data->req;
     VirtIODevice *vdev = VIRTIO_DEVICE(req->dev);
     struct iovec *in_iov = data->in_iov;
     unsigned in_num = data->in_num;
-    int64_t zrp_size, n, j = 0;
-    int64_t nz = data->zone_report_data.nr_zones;
+    int64_t n;
+    int64_t nz = zrd->nr_zones;
     int8_t err_status = VIRTIO_BLK_S_OK;
-    struct virtio_blk_zone_report zrp_hdr = (struct virtio_blk_zone_report) {
-        .nr_zones = cpu_to_le64(nz),
-    };
+    struct virtio_blk_zone_report zrp_hdr = {};
 
     trace_virtio_blk_zone_report_complete(vdev, req, nz, ret);
     if (ret) {
@@ -529,28 +538,18 @@ static void virtio_blk_zone_report_complete(void *opaque, int ret)
         goto out;
     }
 
-    zrp_size = sizeof(struct virtio_blk_zone_report)
-               + sizeof(struct virtio_blk_zone_descriptor) * nz;
-    n = iov_from_buf(in_iov, in_num, 0, &zrp_hdr, sizeof(zrp_hdr));
-    if (n != sizeof(zrp_hdr)) {
-        virtio_error(vdev, "Driver provided input buffer that is too small!");
-        err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
-        goto out;
-    }
-
-    for (size_t i = sizeof(zrp_hdr); i < zrp_size;
-        i += sizeof(struct virtio_blk_zone_descriptor), ++j) {
+    for (size_t j = 0; j < nz; j++) {
         struct virtio_blk_zone_descriptor desc =
             (struct virtio_blk_zone_descriptor) {
-                .z_start = cpu_to_le64(data->zone_report_data.zones[j].start
+                .z_start = cpu_to_le64(zrd->zones[j].start
                     >> BDRV_SECTOR_BITS),
-                .z_cap = cpu_to_le64(data->zone_report_data.zones[j].cap
+                .z_cap = cpu_to_le64(zrd->zones[j].cap
                     >> BDRV_SECTOR_BITS),
-                .z_wp = cpu_to_le64(data->zone_report_data.zones[j].wp
+                .z_wp = cpu_to_le64(zrd->zones[j].wp
                     >> BDRV_SECTOR_BITS),
         };
 
-        switch (data->zone_report_data.zones[j].type) {
+        switch (zrd->zones[j].type) {
         case BLK_ZT_CONV:
             desc.z_type = VIRTIO_BLK_ZT_CONV;
             break;
@@ -564,7 +563,7 @@ static void virtio_blk_zone_report_complete(void *opaque, int ret)
             g_assert_not_reached();
         }
 
-        switch (data->zone_report_data.zones[j].state) {
+        switch (zrd->zones[j].state) {
         case BLK_ZS_RDONLY:
             desc.z_state = VIRTIO_BLK_ZS_RDONLY;
             break;
@@ -594,18 +593,47 @@ static void virtio_blk_zone_report_complete(void *opaque, int ret)
         }
 
         /* TODO: it takes O(n^2) time complexity. Optimizations required. */
-        n = iov_from_buf(in_iov, in_num, i, &desc, sizeof(desc));
+        n = iov_from_buf(in_iov, in_num, zrd->iov_offset, &desc, sizeof(desc));
         if (n != sizeof(desc)) {
             virtio_error(vdev, "Driver provided input buffer "
                                "for descriptors that is too small!");
             err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
+            goto out;
         }
+
+        zrd->iov_offset += sizeof(desc);
+    }
+
+    if (nz > 0) {
+        BlockZoneDescriptor *zone = &zrd->zones[nz - 1];
+        zrd->offset = zone->start + zone->length;
+    }
+
+    zrd->nr_zones_done += nz;
+
+    /* Call zone report again if the end hasn't been reached yet */
+    if (nz == zrd->zones_per_batch &&
+        zrd->nr_zones_done < zrd->total_nr_zones) {
+        zrd->nr_zones = MIN(zrd->zones_per_batch,
+                            zrd->total_nr_zones - zrd->nr_zones_done);
+        blk_aio_zone_report(req->dev->blk, zrd->offset, &zrd->nr_zones,
+                            zrd->zones, virtio_blk_zone_report_complete, data);
+        return;
+    }
+
+    /* Fill in header now that all zones have been reported */
+    zrp_hdr.nr_zones = cpu_to_le64(zrd->nr_zones_done);
+    n = iov_from_buf(in_iov, in_num, 0, &zrp_hdr, sizeof(zrp_hdr));
+    if (n != sizeof(zrp_hdr)) {
+        virtio_error(vdev, "Driver provided input buffer that is too small!");
+        err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
+        goto out;
     }
 
 out:
     virtio_blk_req_complete(req, err_status);
     g_free(req);
-    g_free(data->zone_report_data.zones);
+    g_free(zrd->zones);
     g_free(data);
 }
 
@@ -617,7 +645,8 @@ static void virtio_blk_handle_zone_report(VirtIOBlockReq *req,
     VirtIODevice *vdev = VIRTIO_DEVICE(s);
     unsigned int nr_zones;
     ZoneCmdData *data;
-    int64_t zone_size, offset;
+    ZoneReportData *zrd;
+    int64_t offset;
     uint8_t err_status;
 
     if (req->in_len < sizeof(struct virtio_blk_inhdr) +
@@ -639,16 +668,21 @@ static void virtio_blk_handle_zone_report(VirtIOBlockReq *req,
     trace_virtio_blk_handle_zone_report(vdev, req,
                                         offset >> BDRV_SECTOR_BITS, nr_zones);
 
-    zone_size = sizeof(BlockZoneDescriptor) * nr_zones;
     data = g_malloc(sizeof(ZoneCmdData));
     data->req = req;
     data->in_iov = in_iov;
     data->in_num = in_num;
-    data->zone_report_data.nr_zones = nr_zones;
-    data->zone_report_data.zones = g_malloc(zone_size),
 
-    blk_aio_zone_report(s->blk, offset, &data->zone_report_data.nr_zones,
-                        data->zone_report_data.zones,
+    zrd = &data->zone_report_data;
+    zrd->total_nr_zones = nr_zones;
+    zrd->nr_zones_done = 0;
+    zrd->iov_offset = sizeof(struct virtio_blk_zone_report);
+    zrd->offset = offset;
+    zrd->zones_per_batch = MIN(nr_zones, VIRTIO_BLK_MAX_ZONES_PER_BATCH);
+    zrd->zones = g_malloc(zrd->zones_per_batch * sizeof(BlockZoneDescriptor));
+
+    zrd->nr_zones = zrd->zones_per_batch;
+    blk_aio_zone_report(s->blk, offset, &zrd->nr_zones, zrd->zones,
                         virtio_blk_zone_report_complete, data);
     return;
 out:
-- 
2.53.0
Re: [PATCH for-11.0] virtio-blk: fix zone report buffer out-of-memory (CVE-2026-5761)
Posted by Damien Le Moal 1 day, 11 hours ago
On 2026/04/09 22:07, Stefan Hajnoczi wrote:
> An internal buffer is used when processing VIRTIO_BLK_T_ZONE_REPORT
> requests. The buffer's size is controlled by the guest. A large value
> can result in g_malloc() failure and the QEMU process aborts, resulting
> in a Denial of Service (DoS) (most likely in cases where an untrusted
> guest application or a nested guest with virtio-blk passthrough is able
> to abort QEMU).
> 
> Modify the zone report implementation to work incrementally with a
> bounded buffer size.
> 
> This is purely a QEMU implementation issue and no VIRTIO spec changes
> are needed.
> 
> Mingyuan Luo found this bug and provided a reproducer which I haven't
> put into tests/qtest/ because it requires a zoned storage device (e.g.
> root and modprobe null_blk):
> 
> 1) Prepare a zoned nullblk backend (/dev/nullb0):
> 
> sudo modprobe -r null_blk || true
> sudo modprobe null_blk nr_devices=1 zoned=1
> sudo chmod 0666 /dev/nullb0
> cat /sys/block/nullb0/queue/zoned
> 
> 2) Create qtest input:
> 
> cat >/tmp/vblk-zone-report-oom.qtest <<'EOF'
> outl 0xcf8 0x80002004
> outw 0xcfc 0x0007
> outl 0xcf8 0x80002010
> outl 0xcfc 0x0000c001
> outb 0xc012 0x00
> outb 0xc012 0x01
> outb 0xc012 0x03
> outl 0xc004 0x00000000
> outw 0xc00e 0x0000
> outl 0xc008 0x00000100
> outb 0xc012 0x07
> writel 0x00020000 0x00000010
> writel 0x00020004 0x00000000
> writeq 0x00020008 0x0000000000000000
> writeq 0x00100000 0x0000000000020000
> writel 0x00100008 0x00000010
> writew 0x0010000c 0x0001
> writew 0x0010000e 0x0001
> EOF
> 
> for i in $(seq 1 1022); do
> d=$((0x00100000 + i * 16))
> n=$((i + 1))
> printf 'writeq 0x%08x 0x0000000000200000\n' "$d" >> /tmp/vblk-zone-report-oom.qtest
> printf 'writel 0x%08x 0x1fe00000\n' $((d + 8)) >> /tmp/vblk-zone-report-oom.qtest
> printf 'writew 0x%08x 0x0003\n' $((d + 12)) >> /tmp/vblk-zone-report-oom.qtest
> printf 'writew 0x%08x 0x%04x\n' $((d + 14)) "$n" >> /tmp/vblk-zone-report-oom.qtest
> done
> 
> d=$((0x00100000 + 1023 * 16))
> printf 'writeq 0x%08x 0x0000000000200000\n' "$d" >> /tmp/vblk-zone-report-oom.qtest
> printf 'writel 0x%08x 0x1fe00000\n' $((d + 8)) >> /tmp/vblk-zone-report-oom.qtest
> printf 'writew 0x%08x 0x0002\n' $((d + 12)) >> /tmp/vblk-zone-report-oom.qtest
> printf 'writew 0x%08x 0x0000\n' $((d + 14)) >> /tmp/vblk-zone-report-oom.qtest
> cat >> /tmp/vblk-zone-report-oom.qtest <<'EOF'
> writew 0x00104000 0x0000
> writew 0x00104002 0x0001
> writew 0x00104004 0x0000
> outw 0xc010 0x0000
> EOF
> 
> 3) Run the qtest input with ASAN build (compile qemu with --enable-asan):
> 
> build/qemu-system-x86_64 -display none \
> -accel qtest -qtest stdio \
> -machine pc -nodefaults -m 512M -monitor none -serial none \
> -blockdev driver=host_device,node-name=disk0,filename=/dev/nullb0 \
> -device virtio-blk-pci-transitional,drive=disk0,addr=04.0,queue-size=1024 \
> < /tmp/vblk-zone-report-oom.qtest
> 
> Cc: Sam Li <faithilikerun@gmail.com>
> Cc: Damien Le Moal <dlemoal@kernel.org>
> Cc: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> Fixes: CVE-2026-5761
> Fixes: 4f7366506a9 ("virtio-blk: add zoned storage emulation for zoned devices")
> Reported-by: Mingyuan Luo <myluo24@m.fudan.edu.cn>
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>

Overall, looks OK to me, modulo one nit below.

With that fixed, feel free to add:

Reviewed-by: Damien Le Moal <dlemoal@kernel.org>

[...]

> @@ -529,28 +538,18 @@ static void virtio_blk_zone_report_complete(void *opaque, int ret)
>          goto out;
>      }
>  
> -    zrp_size = sizeof(struct virtio_blk_zone_report)
> -               + sizeof(struct virtio_blk_zone_descriptor) * nz;
> -    n = iov_from_buf(in_iov, in_num, 0, &zrp_hdr, sizeof(zrp_hdr));
> -    if (n != sizeof(zrp_hdr)) {
> -        virtio_error(vdev, "Driver provided input buffer that is too small!");
> -        err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
> -        goto out;
> -    }
> -
> -    for (size_t i = sizeof(zrp_hdr); i < zrp_size;
> -        i += sizeof(struct virtio_blk_zone_descriptor), ++j) {
> +    for (size_t j = 0; j < nz; j++) {

nz is an int64_t, so signed, but j is an unsigned size_t. This can generate
compiler/code checker warnings.


-- 
Damien Le Moal
Western Digital Research
Re: [PATCH for-11.0] virtio-blk: fix zone report buffer out-of-memory (CVE-2026-5761)
Posted by Stefan Hajnoczi 1 day, 3 hours ago
On Fri, Apr 10, 2026 at 05:58:53AM +0200, Damien Le Moal wrote:
> On 2026/04/09 22:07, Stefan Hajnoczi wrote:
> > An internal buffer is used when processing VIRTIO_BLK_T_ZONE_REPORT
> > requests. The buffer's size is controlled by the guest. A large value
> > can result in g_malloc() failure and the QEMU process aborts, resulting
> > in a Denial of Service (DoS) (most likely in cases where an untrusted
> > guest application or a nested guest with virtio-blk passthrough is able
> > to abort QEMU).
> > 
> > Modify the zone report implementation to work incrementally with a
> > bounded buffer size.
> > 
> > This is purely a QEMU implementation issue and no VIRTIO spec changes
> > are needed.
> > 
> > Mingyuan Luo found this bug and provided a reproducer which I haven't
> > put into tests/qtest/ because it requires a zoned storage device (e.g.
> > root and modprobe null_blk):
> > 
> > 1) Prepare a zoned nullblk backend (/dev/nullb0):
> > 
> > sudo modprobe -r null_blk || true
> > sudo modprobe null_blk nr_devices=1 zoned=1
> > sudo chmod 0666 /dev/nullb0
> > cat /sys/block/nullb0/queue/zoned
> > 
> > 2) Create qtest input:
> > 
> > cat >/tmp/vblk-zone-report-oom.qtest <<'EOF'
> > outl 0xcf8 0x80002004
> > outw 0xcfc 0x0007
> > outl 0xcf8 0x80002010
> > outl 0xcfc 0x0000c001
> > outb 0xc012 0x00
> > outb 0xc012 0x01
> > outb 0xc012 0x03
> > outl 0xc004 0x00000000
> > outw 0xc00e 0x0000
> > outl 0xc008 0x00000100
> > outb 0xc012 0x07
> > writel 0x00020000 0x00000010
> > writel 0x00020004 0x00000000
> > writeq 0x00020008 0x0000000000000000
> > writeq 0x00100000 0x0000000000020000
> > writel 0x00100008 0x00000010
> > writew 0x0010000c 0x0001
> > writew 0x0010000e 0x0001
> > EOF
> > 
> > for i in $(seq 1 1022); do
> > d=$((0x00100000 + i * 16))
> > n=$((i + 1))
> > printf 'writeq 0x%08x 0x0000000000200000\n' "$d" >> /tmp/vblk-zone-report-oom.qtest
> > printf 'writel 0x%08x 0x1fe00000\n' $((d + 8)) >> /tmp/vblk-zone-report-oom.qtest
> > printf 'writew 0x%08x 0x0003\n' $((d + 12)) >> /tmp/vblk-zone-report-oom.qtest
> > printf 'writew 0x%08x 0x%04x\n' $((d + 14)) "$n" >> /tmp/vblk-zone-report-oom.qtest
> > done
> > 
> > d=$((0x00100000 + 1023 * 16))
> > printf 'writeq 0x%08x 0x0000000000200000\n' "$d" >> /tmp/vblk-zone-report-oom.qtest
> > printf 'writel 0x%08x 0x1fe00000\n' $((d + 8)) >> /tmp/vblk-zone-report-oom.qtest
> > printf 'writew 0x%08x 0x0002\n' $((d + 12)) >> /tmp/vblk-zone-report-oom.qtest
> > printf 'writew 0x%08x 0x0000\n' $((d + 14)) >> /tmp/vblk-zone-report-oom.qtest
> > cat >> /tmp/vblk-zone-report-oom.qtest <<'EOF'
> > writew 0x00104000 0x0000
> > writew 0x00104002 0x0001
> > writew 0x00104004 0x0000
> > outw 0xc010 0x0000
> > EOF
> > 
> > 3) Run the qtest input with ASAN build (compile qemu with --enable-asan):
> > 
> > build/qemu-system-x86_64 -display none \
> > -accel qtest -qtest stdio \
> > -machine pc -nodefaults -m 512M -monitor none -serial none \
> > -blockdev driver=host_device,node-name=disk0,filename=/dev/nullb0 \
> > -device virtio-blk-pci-transitional,drive=disk0,addr=04.0,queue-size=1024 \
> > < /tmp/vblk-zone-report-oom.qtest
> > 
> > Cc: Sam Li <faithilikerun@gmail.com>
> > Cc: Damien Le Moal <dlemoal@kernel.org>
> > Cc: Dmitry Fomichev <dmitry.fomichev@wdc.com>
> > Fixes: CVE-2026-5761
> > Fixes: 4f7366506a9 ("virtio-blk: add zoned storage emulation for zoned devices")
> > Reported-by: Mingyuan Luo <myluo24@m.fudan.edu.cn>
> > Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> 
> Overall, looks OK to me, modulo one nit below.
> 
> With that fixed, feel free to add:
> 
> Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
> 
> [...]
> 
> > @@ -529,28 +538,18 @@ static void virtio_blk_zone_report_complete(void *opaque, int ret)
> >          goto out;
> >      }
> >  
> > -    zrp_size = sizeof(struct virtio_blk_zone_report)
> > -               + sizeof(struct virtio_blk_zone_descriptor) * nz;
> > -    n = iov_from_buf(in_iov, in_num, 0, &zrp_hdr, sizeof(zrp_hdr));
> > -    if (n != sizeof(zrp_hdr)) {
> > -        virtio_error(vdev, "Driver provided input buffer that is too small!");
> > -        err_status = VIRTIO_BLK_S_ZONE_INVALID_CMD;
> > -        goto out;
> > -    }
> > -
> > -    for (size_t i = sizeof(zrp_hdr); i < zrp_size;
> > -        i += sizeof(struct virtio_blk_zone_descriptor), ++j) {
> > +    for (size_t j = 0; j < nz; j++) {
> 
> nz is an int64_t, so signed, but j is an unsigned size_t. This can generate
> compiler/code checker warnings.

Hi Damien,
Thanks for the review! blk_aio_report_zones() takes an unsigned int
*nr_zones in/out argument and that's also the type of the
ZoneReportData->nr_zones field that nz is initialized from. So I ended
up changing both nz and j's types to unsigned since that is ultimately
the type that blk_aio_report_zones() uses. The int64_t range wasn't
actually being used and size_t wasn't necessary since the value is
capped by nz.

I will send a v2 with the following change on top:

diff --git i/hw/block/virtio-blk.c w/hw/block/virtio-blk.c
index 7fd883320a..9cb9f1fb2b 100644
--- i/hw/block/virtio-blk.c
+++ w/hw/block/virtio-blk.c
@@ -528,7 +528,7 @@ static void virtio_blk_zone_report_complete(void *opaque, int ret)
     struct iovec *in_iov = data->in_iov;
     unsigned in_num = data->in_num;
     int64_t n;
-    int64_t nz = zrd->nr_zones;
+    unsigned nz = zrd->nr_zones;
     int8_t err_status = VIRTIO_BLK_S_OK;
     struct virtio_blk_zone_report zrp_hdr = {};

@@ -538,7 +538,7 @@ static void virtio_blk_zone_report_complete(void *opaque, int ret)
         goto out;
     }

-    for (size_t j = 0; j < nz; j++) {
+    for (unsigned j = 0; j < nz; j++) {
         struct virtio_blk_zone_descriptor desc =
             (struct virtio_blk_zone_descriptor) {
                 .z_start = cpu_to_le64(zrd->zones[j].start