aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/bhyve
diff options
context:
space:
mode:
authorChuck Tuffli <chuck@FreeBSD.org>2021-06-27 22:14:52 +0000
committerChuck Tuffli <chuck@FreeBSD.org>2021-06-27 22:14:52 +0000
commit91064841d72b285a146a3f1c32cb447251e062ea (patch)
tree95003da00ce7f2278313c2f9ed5a0128e36b6d0a /usr.sbin/bhyve
parentc7f048ab3532a9f081addd6da0adf96f25271de8 (diff)
downloadsrc-91064841d72b285a146a3f1c32cb447251e062ea.tar.gz
src-91064841d72b285a146a3f1c32cb447251e062ea.zip
bhyve: Fix NVMe iovec construction for large IOs
The UEFI driver included with Rocky Linux 8.4 uncovered an existing bug in the NVMe emulation's construction of iovec's. By default, NVMe data transfer operations use a scatter-gather list in which all entries point to a fixed size memory region. For example, if the Memory Page Size is 4KiB, a 2MiB IO requires 512 entries. Lists themselves are also fixed size (default is 512 entries). Because the list size is fixed, the last entry is special. If the IO requires more than 512 entries, the last entry in the list contains the address of the next list of entries. But if the IO requires exactly 512 entries, the last entry points to data. The NVMe emulation missed this logic and unconditionally treated the last entry as a pointer to the next list. Fix is to check if the remaining data is greater than the page size before using the last entry as a pointer to the next list. PR: 256422 Reported by: dave@syix.com Tested by: jason@tubnor.net MFC after: 5 days Relnotes: yes Reviewed by: imp, grehan Differential Revision: https://reviews.freebsd.org/D30897
Diffstat (limited to 'usr.sbin/bhyve')
-rw-r--r--usr.sbin/bhyve/pci_nvme.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/usr.sbin/bhyve/pci_nvme.c b/usr.sbin/bhyve/pci_nvme.c
index 414edabc2b7c..fa316fa285db 100644
--- a/usr.sbin/bhyve/pci_nvme.c
+++ b/usr.sbin/bhyve/pci_nvme.c
@@ -1976,7 +1976,7 @@ nvme_write_read_blockif(struct pci_nvme_softc *sc,
/* PRP2 is pointer to a physical region page list */
while (bytes) {
/* Last entry in list points to the next list */
- if (prp_list == last) {
+ if ((prp_list == last) && (bytes > PAGE_SIZE)) {
uint64_t prp = *prp_list;
prp_list = paddr_guest2host(vmctx, prp,