From: Michael Bommarito Date: Sun, 7 Jun 2026 12:48:34 +0000 (-0400) Subject: virtio-blk: clamp zone report to the report buffer capacity X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0fd835f5e9477ebea2439b8ada58f34e1b8cf25a;p=thirdparty%2Flinux.git virtio-blk: clamp zone report to the report buffer capacity virtblk_report_zones() trusts the device-reported number of zones when walking the report buffer: nz = min_t(u64, virtio64_to_cpu(vblk->vdev, report->nr_zones), nr_zones); ... for (i = 0; i < nz && zone_idx < nr_zones; i++) { ret = virtblk_parse_zone(vblk, &report->zones[i], ...); The buffer is allocated by virtblk_alloc_report_buffer(), whose size is capped by the queue's max hardware sectors and max segments and can therefore hold fewer descriptors than nr_zones. nz is bounded only by the device-supplied report->nr_zones and the requested nr_zones, never by the buffer's descriptor capacity. At probe time the request count is unbounded (blk_revalidate_disk_zones() calls report_zones() with nr_zones == UINT_MAX), so the device-supplied report->nr_zones is the sole gate: a device that reports more zones than fit in the buffer drives the loop to read report->zones[i] past the end of the allocation. A malicious or buggy virtio-blk device that reports an inflated nr_zones triggers this during zone revalidation at probe. KASAN reports a vmalloc-out-of-bounds read in virtblk_report_zones() against the report buffer allocated a few lines earlier. Clamp nz to the number of descriptors that actually fit in the report buffer. Fixes: 95bfec41bd3d ("virtio-blk: add support for zoned block devices") Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Michael Bommarito Acked-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi Link: https://patch.msgid.link/20260607124834.3059944-1-michael.bommarito@gmail.com Signed-off-by: Jens Axboe --- diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index b1c9a27fe00f3..32bf3ba07a9dc 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -689,6 +689,8 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector, nz = min_t(u64, virtio64_to_cpu(vblk->vdev, report->nr_zones), nr_zones); + nz = min_t(u64, nz, + (buflen - sizeof(*report)) / sizeof(report->zones[0])); if (!nz) break;