Re: [PATCH v3] scsi: scsi_debug: fix REPORT ZONES alloc_len underflow OOB write

From: Damien Le Moal

Date: Fri Jul 10 2026 - 02:04:11 EST


On 7/10/26 14:57, Ibrahim Hashimov wrote:
> resp_report_zones() derives the number of zone descriptors that fit in
> the reply buffer from the command allocation length:
>
> rep_max_zones = (alloc_len - 64) >> ilog2(RZONES_DESC_HD);
>
> arr = kzalloc(alloc_len, GFP_ATOMIC | __GFP_NOWARN);
>
> alloc_len is taken directly from the CDB and is fully controlled by the
> initiator. When alloc_len is smaller than the 64-byte report header
> (RZONES_DESC_HD), the subtraction underflows and rep_max_zones becomes a
> huge value. The buffer is then allocated with only alloc_len bytes, which
> is smaller than the 64-byte header the code unconditionally writes, and
> the descriptor loop is bounded by the bogus rep_max_zones. Both the header
> store and the following zone descriptors are then written past the end of
> the undersized allocation, corrupting adjacent slab memory.
>
> Fix it by sizing the buffer to a whole number of 64-byte blocks that
> cover the requested allocation length:
>
> rep_max_zones =
> (ALIGN((u64)alloc_len, RZONES_DESC_HD) - RZONES_DESC_HD)
> >> ilog2(RZONES_DESC_HD);
> arr_len = (u64)RZONES_DESC_HD * (rep_max_zones + 1);
>
> arr = kzalloc(arr_len, GFP_ATOMIC | __GFP_NOWARN);
>
> RZONES_DESC_HD is a power of two, so ALIGN() rounds alloc_len up to the
> next multiple of 64 and rep_max_zones can no longer underflow: for any
> alloc_len of 1 to 64 it is 0, so only the header is built. arr_len is
> always RZONES_DESC_HD * (rep_max_zones + 1), which is exactly large enough
> for the header plus every descriptor the loop may write, so the report is
> always assembled within bounds, including a possibly partial trailing
> zone descriptor. The existing copy-out still transfers only what the host
> asked for:
>
> fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len));
>
> so an allocation length that ends in the middle of a zone descriptor
> returns the correctly truncated partial descriptor, as permitted by the
> SCSI/ZBC specifications, while never reading past arr_len.
>
> The aligned length and the buffer size are computed in 64-bit (alloc_len
> is cast to u64 before ALIGN and the size product uses a u64 block size) so
> a crafted allocation length near U32_MAX cannot wrap them to a small value;
> such a request simply fails the large allocation and returns a check
> condition instead of overflowing the buffer.
>
> This was found by static analysis. A KASAN slab-out-of-bounds runtime
> reproduction of the original underflow is being re-run against the ALIGN
> based fix and will be reported separately.
>
> Fixes: 7db0e0c8190a ("scsi: scsi_debug: Fix buffer size of REPORT ZONES command")
> Suggested-by: Damien Le Moal <dlemoal@xxxxxxxxxx>
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Ibrahim Hashimov <security@xxxxxxxxxxxx>
> Assisted-by: AuditCode-AI:2026.07

Looks OK to me.

Reviewed-by: Damien Le Moal <dlemoal@xxxxxxxxxx>

--
Damien Le Moal
Western Digital Research