diff options
| author | Kenneth D. Merry <ken@FreeBSD.org> | 2026-11-09 19:35:00 +0000 |
|---|---|---|
| committer | Kenneth D. Merry <ken@FreeBSD.org> | 2026-11-10 20:04:33 +0000 |
| commit | eae727676169de58052fd512ebb0ee565ad6e246 (patch) | |
| tree | d63097706dc4dea6d67b665f1ad929a0bf0ae863 | |
| parent | 7ac5569c5d9e601201c811786e6d0026f8aa3c1b (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.c | 15 |
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"); |
