git: 50ca525bfe96 - releng/13.3 - bhyve/nvme: Fix out-of-bounds read in NVMe log page

From: Ed Maste <emaste_at_FreeBSD.org>
Date: Tue, 29 Oct 2024 18:53:36 UTC
The branch releng/13.3 has been updated by emaste:

URL: https://cgit.FreeBSD.org/src/commit/?id=50ca525bfe9633c887029b8aaeafc605a5414831

commit 50ca525bfe9633c887029b8aaeafc605a5414831
Author:     Chuck Tuffli <chuck@FreeBSD.org>
AuthorDate: 2024-09-19 15:11:30 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2024-10-29 18:52:43 +0000

    bhyve/nvme: Fix out-of-bounds read in NVMe log page
    
    The function nvme_opc_get_log_page in the file usr.sbin/bhyve/pci_nvme.c
    is vulnerable to buffer over-read. The value logoff is user controlled
    but never checked against the value of logsize. Thus the difference:
            logsize - logoff
    can underflow.
    
    Due to the sc structure layout, an attacker can dump internals fields of
    sc and the content of next heap allocation.
    
    Reported by:    Synacktiv
    Reviewed by:    emaste, jhb
    Security:       HYP-07
    Security:       FreeBSD-SA-24:17.bhyve
    Approved by:    so
    Sponsored by:   The Alpha-Omega Project
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D46021
    
    (cherry picked from commit b0a24be007d83f7929de5b3fc320a29e6868067d)
    (cherry picked from commit a5be19efbb7c6b07d574ef048b2ebade00440873)
    (cherry picked from commit c8f75686adc6bc2078ade279d838cbc5b1745e71)
---
 usr.sbin/bhyve/pci_nvme.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/usr.sbin/bhyve/pci_nvme.c b/usr.sbin/bhyve/pci_nvme.c
index 3db306a19119..cbe4d87b6f60 100644
--- a/usr.sbin/bhyve/pci_nvme.c
+++ b/usr.sbin/bhyve/pci_nvme.c
@@ -1454,7 +1454,7 @@ nvme_opc_get_log_page(struct pci_nvme_softc* sc, struct nvme_command* command,
 	logsize *= sizeof(uint32_t);
 	logoff  = ((uint64_t)(command->cdw13) << 32) | command->cdw12;
 
-	DPRINTF("%s log page %u len %u", __func__, logpage, logsize);
+	DPRINTF("%s log page %u offset %lu len %u", __func__, logpage, logoff, logsize);
 
 	switch (logpage) {
 	case NVME_LOG_ERROR:
@@ -1466,7 +1466,7 @@ nvme_opc_get_log_page(struct pci_nvme_softc* sc, struct nvme_command* command,
 
 		nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1,
 		    command->prp2, (uint8_t *)&sc->err_log + logoff,
-		    MIN(logsize - logoff, sizeof(sc->err_log)),
+		    MIN(logsize, sizeof(sc->err_log) - logoff),
 		    NVME_COPY_TO_PRP);
 		break;
 	case NVME_LOG_HEALTH_INFORMATION:
@@ -1489,7 +1489,7 @@ nvme_opc_get_log_page(struct pci_nvme_softc* sc, struct nvme_command* command,
 
 		nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1,
 		    command->prp2, (uint8_t *)&sc->health_log + logoff,
-		    MIN(logsize - logoff, sizeof(sc->health_log)),
+		    MIN(logsize, sizeof(sc->health_log) - logoff),
 		    NVME_COPY_TO_PRP);
 		break;
 	case NVME_LOG_FIRMWARE_SLOT:
@@ -1501,7 +1501,7 @@ nvme_opc_get_log_page(struct pci_nvme_softc* sc, struct nvme_command* command,
 
 		nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1,
 		    command->prp2, (uint8_t *)&sc->fw_log + logoff,
-		    MIN(logsize - logoff, sizeof(sc->fw_log)),
+		    MIN(logsize, sizeof(sc->fw_log) - logoff),
 		    NVME_COPY_TO_PRP);
 		break;
 	case NVME_LOG_CHANGED_NAMESPACE:
@@ -1513,7 +1513,7 @@ nvme_opc_get_log_page(struct pci_nvme_softc* sc, struct nvme_command* command,
 
 		nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1,
 		    command->prp2, (uint8_t *)&sc->ns_log + logoff,
-		    MIN(logsize - logoff, sizeof(sc->ns_log)),
+		    MIN(logsize, sizeof(sc->ns_log) - logoff),
 		    NVME_COPY_TO_PRP);
 		memset(&sc->ns_log, 0, sizeof(sc->ns_log));
 		break;