All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ibrahim Hashimov <security@auditcode.ai>
To: martin.petersen@oracle.com,
	James.Bottomley@HansenPartnership.com, dlemoal@kernel.org
Cc: shinichiro.kawasaki@wdc.com, damien.lemoal@opensource.wdc.com,
	linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org,
	stable@vger.kernel.org
Subject: [PATCH v3] scsi: scsi_debug: fix REPORT ZONES alloc_len underflow OOB write
Date: Fri, 10 Jul 2026 07:57:55 +0200	[thread overview]
Message-ID: <20260710055755.53830-1-security@auditcode.ai> (raw)
In-Reply-To: <1357dbf9-e135-4ba3-896d-1472a208f82f@kernel.org>

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@kernel.org>
Cc: stable@vger.kernel.org
Signed-off-by: Ibrahim Hashimov <security@auditcode.ai>
Assisted-by: AuditCode-AI:2026.07
---
v3: adopt Damien Le Moal's ALIGN-based buffer sizing (Suggested-by) so a
partial trailing zone descriptor is filled and returned per the SCSI/ZBC
specs; v2 emitted only the report header for allocation lengths of 65..127
bytes. The buffer is sized to a whole number of 64-byte blocks covering
alloc_len; the existing min(alloc_len, rep_len) copy-out still truncates the
transfer to the requested length.
Computed in 64-bit to avoid a u32 wrap of the aligned length/size for
allocation lengths near U32_MAX (which would otherwise reintroduce the
overflow).
v2: https://lore.kernel.org/linux-scsi/20260709194824.50777-1-security@auditcode.ai/
 drivers/scsi/scsi_debug.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 9d1c9c41d0f9..12e5a8624511 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -5890,6 +5890,7 @@ static int resp_report_zones(struct scsi_cmnd *scp,
 	u32 alloc_len, rep_opts, rep_len;
 	bool partial;
 	u64 lba, zs_lba;
+	u64 arr_len;
 	u8 *arr = NULL, *desc;
 	u8 *cmd = scp->cmnd;
 	struct sdeb_zone_state *zsp = NULL;
@@ -5911,9 +5912,11 @@ static int resp_report_zones(struct scsi_cmnd *scp,
 		return check_condition_result;
 	}
 
-	rep_max_zones = (alloc_len - 64) >> ilog2(RZONES_DESC_HD);
+	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(alloc_len, GFP_ATOMIC | __GFP_NOWARN);
+	arr = kzalloc(arr_len, GFP_ATOMIC | __GFP_NOWARN);
 	if (!arr) {
 		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
 				INSUFF_RES_ASCQ);
-- 
2.50.1 (Apple Git-155)


  reply	other threads:[~2026-07-10  5:58 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-09 15:06 [PATCH] scsi: scsi_debug: fix REPORT ZONES alloc_len underflow OOB write Ibrahim Hashimov
2026-07-09 15:18 ` sashiko-bot
2026-07-09 19:48 ` [PATCH v2] " Ibrahim Hashimov
2026-07-10  0:58   ` Damien Le Moal
2026-07-10  5:57     ` Ibrahim Hashimov [this message]
2026-07-10  6:03       ` [PATCH v3] " Damien Le Moal
2026-07-10  6:05       ` sashiko-bot
2026-07-10 14:37         ` Bart Van Assche
2026-07-12 18:36           ` Ibrahim Hashimov
2026-07-12 18:37       ` [PATCH v4] " Ibrahim Hashimov
2026-07-13  5:43         ` Damien Le Moal
2026-07-13 17:12         ` Bart Van Assche
2026-07-10  5:59     ` [PATCH v2] " Ibrahim Hashimov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260710055755.53830-1-security@auditcode.ai \
    --to=security@auditcode.ai \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=damien.lemoal@opensource.wdc.com \
    --cc=dlemoal@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=martin.petersen@oracle.com \
    --cc=shinichiro.kawasaki@wdc.com \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.