[PATCH AUTOSEL 6.18-5.15] nvmet: zns: reject full zone report when buffer is too small
sashiko-bot at kernel.org
sashiko-bot at kernel.org
Mon Oct 19 07:15:36 PDT 2026
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] nvmet: zns: broken PR=0 zone reports in nvmet_bdev_zone_zmgmt_recv_work()
--
commit 42bb4c679b1e6318e7ed82bbe79461a255997505
Author: Xixin Liu <liuxixin at kylinos.cn>
nvmet: zns: reject full zone report when buffer is too small
This patch updates nvmet_bdev_zone_zmgmt_recv_work() in
drivers/nvme/target/zns.c to fail Zone Management Receive commands with
NVME_SC_INVALID_FIELD | NVME_STATUS_DNR when the Partial Report (PR) bit is
clear and rz_data.nr_zones exceeds rz_data.out_nr_zones.
> diff --git a/drivers/nvme/target/zns.c b/drivers/nvme/target/zns.c
> index 15a579cf528c1..dfa9269b59992 100644
> --- a/drivers/nvme/target/zns.c
> +++ b/drivers/nvme/target/zns.c
> @@ -299,11 +299,18 @@ static void nvmet_bdev_zone_zmgmt_recv_work(struct work_struct *w)
> }
>
> /*
> - * When partial bit is set nr_zones must indicate the number of zone
> - * descriptors actually transferred.
> + * Partial report (PR bit set): the host accepts an incomplete listing,
> + * so cap Number of Zones to the descriptors that fit in the buffer.
> + * Full report (PR bit clear): Number of Zones is the match count; fail
> + * if the buffer cannot hold every matching zone descriptor.
> */
> - if (req->cmd->zmr.pr)
> + if (req->cmd->zmr.pr) {
> rz_data.nr_zones = min(rz_data.nr_zones, rz_data.out_nr_zones);
> + } else if (rz_data.nr_zones > rz_data.out_nr_zones) {
> + req->error_loc = offsetof(struct nvme_zone_mgmt_recv_cmd, numd);
> + status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
> + goto out;
> + }
[Severity: High]
Won't rejecting req->cmd->zmr.pr == 0 commands when rz_data.nr_zones >
rz_data.out_nr_zones break valid non-partial Zone Management Receive
queries?
Per the NVMe Zoned Namespace Command Set specification (section 3.4.2), the
Partial Report (PR) bit controls the value placed in the Number of Zones
field of the 64-byte Report Zones header (struct nvme_zone_report):
- When PR is 0, Number of Zones indicates the total number of zones matching
the ZRASF criteria from SLBA to the end of the namespace, regardless of the
size of the data buffer, while only as many zone descriptors as fit in the
buffer are transferred.
- When PR is 1, Number of Zones indicates the number of zone descriptors
actually transferred in the buffer.
The only NUMD buffer size condition that aborts the command with Invalid
Field in Command is when the buffer is smaller than the 64-byte Report Zones
header itself, which nvmet_bdev_validate_zone_mgmt_recv() already checks:
drivers/nvme/target/zns.c:nvmet_bdev_validate_zone_mgmt_recv() {
...
if (out_bufsize < sizeof(struct nvme_zone_report)) {
req->error_loc = offsetof(struct nvme_zone_mgmt_recv_cmd, numd);
return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
}
...
}
The existing helpers in drivers/nvme/target/zns.c are built around this
behavior. In particular, get_nr_zones_from_buf() explicitly allows a 64-byte
header-only buffer (returning out_nr_zones == 0) so an initiator can issue a
PR=0 command to discover the total number of matching zones before allocating
a full descriptor buffer:
drivers/nvme/target/zns.c:get_nr_zones_from_buf() {
if (bufsize <= sizeof(struct nvme_zone_report))
return 0;
return (bufsize - sizeof(struct nvme_zone_report)) /
sizeof(struct nvme_zone_descriptor);
}
And nvmet_bdev_report_zone_cb() copies descriptors into the host SGL only
while rz->nr_zones < rz->out_nr_zones, yet continues incrementing
rz->nr_zones across all remaining matching zones specifically to compute the
total match count for PR=0:
drivers/nvme/target/zns.c:nvmet_bdev_report_zone_cb() {
...
if (rz->nr_zones < rz->out_nr_zones) {
...
status = nvmet_copy_to_sgl(rz->req, rz->out_buf_offset, &zdesc,
sizeof(zdesc));
if (status)
return -EINVAL;
rz->out_buf_offset += sizeof(zdesc);
}
rz->nr_zones++;
return 0;
}
With this new check in nvmet_bdev_zone_zmgmt_recv_work(), any 64-byte
header-only PR=0 query (out_nr_zones == 0) fails with NVME_SC_INVALID_FIELD |
NVME_STATUS_DNR whenever at least one zone matches, and any bounded-buffer
PR=0 query fails after nvmet_bdev_report_zone_cb() has already written
out_nr_zones descriptors into the host SGL.
>
> nr_zones = cpu_to_le64(rz_data.nr_zones);
> status = nvmet_copy_to_sgl(req, 0, &nr_zones, sizeof(nr_zones));
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261019135441.1420968-69-sashal@kernel.org?part=1
More information about the Linux-nvme
mailing list