* [PATCH] nvme: reject zoned namespaces whose zone info query failed
@ 2026-08-14 16:09 Chao Shi
2026-08-14 19:28 ` Keith Busch
0 siblings, 1 reply; 2+ messages in thread
From: Chao Shi @ 2026-08-14 16:09 UTC (permalink / raw)
To: kbusch
Cc: hch, sagi, axboe, joshi.k, weizhu, linux-nvme, linux-kernel,
stable, Chao Shi
nvme_query_zone_info() returns either a negative errno or a positive NVMe
status code, but nvme_update_ns_info_block() only tests for the negative
case:
ret = nvme_query_zone_info(ns, lbaf, &zi);
if (ret < 0)
goto out;
If the Identify Namespace (I/O Command Set specific) command fails on the
device, or if the Identify Controller command issued by
nvme_set_max_append() fails, the positive status falls through and setup
continues with the zero-initialized "struct nvme_zone_info zi = {}".
nvme_update_zone_info() then configures the queue from those zeroes:
lim->features |= BLK_FEAT_ZONED;
lim->max_open_zones = zi->max_open_zones;
lim->max_active_zones = zi->max_active_zones;
lim->chunk_sectors = ns->head->zsze =
nvme_lba_to_sect(ns->head, zi->zone_size);
so the queue ends up marked zoned with a zone size of zero. This is
reachable by a malicious NVMe device, a buggy firmware, or an
attacker-controlled NVMe-oF target that fails this one command.
blk_validate_zoned_limits() does not look at chunk_sectors, so the limits
commit succeeds. blk_revalidate_disk_zones() does reject the zero zone
size, but by then the limits are committed and the queue is unfrozen and
nothing rolls them back, so block devices that are already open keep
submitting I/O to a zoned queue whose zone size is zero. disk_zone_no()
then shifts by ilog2(0):
nvme0n1: Invalid non power of two zone size (0)
UBSAN: shift-out-of-bounds in include/linux/blkdev.h:747:16
shift exponent -1 is negative
disk_zone_no include/linux/blkdev.h:747 [inline]
bio_zone_no include/linux/blkdev.h:1052 [inline]
bio_straddles_zones include/linux/blkdev.h:1058 [inline]
blk_zone_wplug_handle_write block/blk-zoned.c:1423 [inline]
blk_zone_plug_bio.cold+0x25/0x1c8 block/blk-zoned.c:1605
blk_mq_submit_bio+0x18fb/0x2870 block/blk-mq.c:3196
__submit_bio+0x315/0xa70 block/blk-core.c:637
submit_bio_noacct_nocheck+0x488/0xba0 block/blk-core.c:755
submit_bh_wbc+0x575/0x740 fs/buffer.c:2824
__block_write_full_folio+0x728/0xdd0 fs/buffer.c:1933
wb_workfn+0x8c9/0xd50 fs/fs-writeback.c:2403
Before commit c85c9ab926a5 ("nvme: split nvme_update_zone_info") the
caller tested "if (ret)" and bailed out on any non-zero return. Restore
that behaviour.
Fixes: c85c9ab926a5 ("nvme: split nvme_update_zone_info")
Cc: stable@vger.kernel.org
Cc: Weidong Zhu <weizhu@fiu.edu>
Found by FuzzNvme.
Signed-off-by: Chao Shi <coshi036@gmail.com>
---
drivers/nvme/host/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 453c1f0b2dd0..dd7859826d2b 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2417,7 +2417,7 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
ns->head->ids.csi == NVME_CSI_ZNS) {
ret = nvme_query_zone_info(ns, lbaf, &zi);
- if (ret < 0)
+ if (ret)
goto out;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] nvme: reject zoned namespaces whose zone info query failed
2026-08-14 16:09 [PATCH] nvme: reject zoned namespaces whose zone info query failed Chao Shi
@ 2026-08-14 19:28 ` Keith Busch
0 siblings, 0 replies; 2+ messages in thread
From: Keith Busch @ 2026-08-14 19:28 UTC (permalink / raw)
To: Chao Shi
Cc: hch, sagi, axboe, joshi.k, weizhu, linux-nvme, linux-kernel,
stable
On Fri, Aug 14, 2026 at 12:09:54PM -0400, Chao Shi wrote:
> Before commit c85c9ab926a5 ("nvme: split nvme_update_zone_info") the
> caller tested "if (ret)" and bailed out on any non-zero return. Restore
> that behaviour.
I think the namespace is generally left up on purpose for controller
reported errors so that we have a device handle for admin debugging
purposes.
Can you just skip the zone limits update when you have a bad response?
Something like:
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2457,7 +2457,8 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
capacity = 0;
if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
- ns->head->ids.csi == NVME_CSI_ZNS)
+ ns->head->ids.csi == NVME_CSI_ZNS &&
+ zi.max_open_zones)
nvme_update_zone_info(ns, &lim, &zi);
if ((ns->ctrl->vwc & NVME_CTRL_VWC_PRESENT) && !info->no_vwc)
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-08-14 19:28 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-14 16:09 [PATCH] nvme: reject zoned namespaces whose zone info query failed Chao Shi
2026-08-14 19:28 ` Keith Busch
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox