aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth D. Merry <ken@FreeBSD.org>2026-11-09 19:35:00 +0000
committerKenneth D. Merry <ken@FreeBSD.org>2026-11-10 20:04:33 +0000
commiteae727676169de58052fd512ebb0ee565ad6e246 (patch)
treed63097706dc4dea6d67b665f1ad929a0bf0ae863
parent7ac5569c5d9e601201c811786e6d0026f8aa3c1b (diff)
nvmecontrol: Mask the fields in the Format NVM command
The format command composed cdw10 by hand without masking any of the fields and with no support for the LBAFU field. Since commit 2c41f7d8a034 the LBA format index defaulted from FLBAS can exceed 15 on an NVMe 2.0 namespace using FIDXU, and such an index would bleed into the MSET and PI fields. An out of range index supplied with -f for a whole-controller format was not caught either. Build the command with nvme_admin_format_cmd(), which masks all of the fields and encodes LBA format indexes above 15 in LBAFU, and reject LBA format indexes greater than 63 for whole-controller formats. Per-namespace formats already validate the index against NLBAF. This is the same problem that llm-postcr reported in camcontrol's copy of this code, fixed in 3892a6453fc6; the unmasked composition originated here (635c517ae9ca). Reported by: llm-postcr Reviewed by: imp Fixes: 2c41f7d8a034 MFC after: 1 week Sponsored by: Spectra Logic Assisted-by: Claude Fable 5 <noreply@anthropic.com> Differential Revision: https://reviews.freebsd.org/D61356
-rw-r--r--sbin/nvmecontrol/format.c15
1 files changed, 7 insertions, 8 deletions
diff --git a/sbin/nvmecontrol/format.c b/sbin/nvmecontrol/format.c
index 2efc0144c232..62dd56a5a81e 100644
--- a/sbin/nvmecontrol/format.c
+++ b/sbin/nvmecontrol/format.c
@@ -190,7 +190,7 @@ format(const struct cmd *f, int argc, char *argv[])
struct nvme_pt_command pt;
char *path;
const char *target;
- uint32_t cdw10, nsid, scan_nsid;
+ uint32_t nsid, scan_nsid;
int lbaf, ms, pi, pil, ses, fd;
u_int i;
uint32_t sector_size;
@@ -312,6 +312,8 @@ format(const struct cmd *f, int argc, char *argv[])
}
if (lbaf < 0)
lbaf = 0;
+ else if (lbaf > 63)
+ errx(EX_USAGE, "LBA format is out of range");
if (ms < 0)
ms = 0;
if (pi < 0)
@@ -320,20 +322,17 @@ format(const struct cmd *f, int argc, char *argv[])
pil = 0;
}
- cdw10 = (ses << 9) + (pil << 8) + (pi << 5) + (ms << 4) + lbaf;
+ memset(&pt, 0, sizeof(pt));
+ nvme_admin_format_cmd(&pt.cmd, nsid, ses, pil, pi, ms, lbaf);
if (opt.dry_run) {
printf("Format NVM: opc=%#x nsid=%#010x cdw10=%#010x "
"(lbaf=%d mset=%d pi=%d pil=%d ses=%d)\n",
- NVME_OPC_FORMAT_NVM, nsid, cdw10, lbaf, ms, pi, pil, ses);
+ NVME_OPC_FORMAT_NVM, nsid, le32toh(pt.cmd.cdw10), lbaf,
+ ms, pi, pil, ses);
close(fd);
exit(0);
}
- memset(&pt, 0, sizeof(pt));
- pt.cmd.opc = NVME_OPC_FORMAT_NVM;
- pt.cmd.nsid = htole32(nsid);
- pt.cmd.cdw10 = htole32(cdw10);
-
if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
err(EX_IOERR, "format request failed");