From: Ibrahim Hashimov <security@auditcode.ai>
To: martin.petersen@oracle.com, James.Bottomley@HansenPartnership.com
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 v2] scsi: scsi_debug: fix REPORT ZONES alloc_len underflow OOB write
Date: Thu, 9 Jul 2026 21:48:24 +0200 [thread overview]
Message-ID: <20260709194824.50777-1-security@auditcode.ai> (raw)
In-Reply-To: <20260709150631.45018-1-security@auditcode.ai>
resp_report_zones() reads the REPORT ZONES(16) ALLOCATION LENGTH field
(cmd[10..13]) into the unsigned alloc_len and, apart from the
alloc_len == 0 fast path, uses it without flooring it against the
64-byte report header:
rep_max_zones = (alloc_len - 64) >> ilog2(RZONES_DESC_HD);
arr = kzalloc(alloc_len, GFP_ATOMIC | __GFP_NOWARN);
...
desc = arr + 64;
For any alloc_len in the range 1..63, alloc_len - 64 wraps around
(alloc_len and rep_max_zones are unsigned), so rep_max_zones becomes a
huge value instead of zero. At the same time arr is allocated with the
raw alloc_len, which is smaller than the 64-byte header the function
always builds, and desc is set to arr + 64, already past the end of the
allocation. The report header stores (put_unaligned_be32 at arr+0,
put_unaligned_be64 at arr+8 and arr+16) can then run past a sub-24-byte
buffer, and the per-zone descriptor loop, no longer bounded by the
inflated rep_max_zones, writes 64-byte descriptors from desc onward,
producing a slab out-of-bounds write.
Fix it the way ZBC and SPC require: allocation length truncation is not
an error, and a small alloc_len is a legitimate probe a host uses to
read the zone list length before allocating a full buffer. Clamp
rep_max_zones to zero when alloc_len is below the header size so no
descriptor is emitted, and size the allocation to at least the header
so the unconditional 64-byte header build cannot overflow. The existing
copy-out already truncates the result with
fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len)), so the
host still receives exactly the alloc_len bytes it asked for. There is
no functional change for alloc_len >= 64.
This supersedes the previous approach of rejecting a sub-header
allocation length with a check condition, which would have broken those
legitimate small-alloc_len probes.
Verified on a v6.19 KASAN build: with scsi_debug loaded as
zbc=host-managed, issuing REPORT ZONES(16) via SG_IO with alloc_len=32
triggers a KASAN slab-out-of-bounds write in resp_report_zones()
before this change, and the same command produces no report once the
clamp and allocation floor are applied. Reproduction requires
CAP_SYS_RAWIO to submit the raw CDB.
Fixes: 7db0e0c8190a ("scsi: scsi_debug: Fix buffer size of REPORT ZONES command")
Cc: stable@vger.kernel.org
Signed-off-by: Ibrahim Hashimov <security@auditcode.ai>
Assisted-by: AuditCode-AI:2026.07
---
v2: address sashiko-bot review of v1
(https://lore.kernel.org/linux-scsi/20260709150631.45018-1-security@auditcode.ai/):
rejecting a sub-header allocation length with a check condition violates the
ZBC/SPC rule that allocation-length truncation is not an error and breaks
legitimate small-alloc_len zone-list-length probes. Instead clamp rep_max_zones
to zero and floor the allocation at the 64-byte header, letting the existing
min(alloc_len, rep_len) copy-out return the truncated header. No functional
change for alloc_len >= 64.
drivers/scsi/scsi_debug.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 9d1c9c41d0f9..a21d76fe35f6 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -5911,9 +5911,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 = (alloc_len < RZONES_DESC_HD) ? 0 :
+ (alloc_len - RZONES_DESC_HD) >> ilog2(RZONES_DESC_HD);
- arr = kzalloc(alloc_len, GFP_ATOMIC | __GFP_NOWARN);
+ arr = kzalloc(max_t(u32, alloc_len, RZONES_DESC_HD),
+ GFP_ATOMIC | __GFP_NOWARN);
if (!arr) {
mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
INSUFF_RES_ASCQ);
--
2.50.1 (Apple Git-155)
next prev parent reply other threads:[~2026-07-09 19:48 UTC|newest]
Thread overview: 12+ 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 ` Ibrahim Hashimov [this message]
2026-07-10 0:58 ` [PATCH v2] " Damien Le Moal
2026-07-10 5:57 ` [PATCH v3] " Ibrahim Hashimov
2026-07-10 6:03 ` 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-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=20260709194824.50777-1-security@auditcode.ai \
--to=security@auditcode.ai \
--cc=James.Bottomley@HansenPartnership.com \
--cc=damien.lemoal@opensource.wdc.com \
--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.