From nobody Tue Oct 29 18:45:36 2024 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4XdK2T2lcsz5bmwV; Tue, 29 Oct 2024 18:45:37 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4XdK2S6W5Vz41Vy; Tue, 29 Oct 2024 18:45:36 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1730227536; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=RjwlfE7sZjcrLdjlibknX8627uSEybI887a2u/AYBh4=; b=W4ZITpKHvDr1u9C93ikTHI7Dzm8nFX7i+vWh9oBRlZcK5t8plJgYNEgQ0pJ5VPgcUnelpj e5K5A8c65OaVH+Apav154P+Wl9cNPGcikFiFUKzEoXrcvuzLv0Dr1UDhOKWu2pyjMA+DP2 FlCJf5TFLMiKf/vurSDUu/HXhLIYDSdAftnh01FLQyuwZsG3ynPj31++9NYshDb4mQ9GMp 6KDVTJYeJF2ixXpFNYM/SH4DbqpsYqzXeUrWHlVZwdJ/UmVX19leHUu1RnZ6XRLAzrOccz hZ16iZ5fFikJpfZJHqpFHcXvNrlkWFmMxVh0kXYNdYUrMI5am2pk6wGn0gGhSQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1730227536; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=RjwlfE7sZjcrLdjlibknX8627uSEybI887a2u/AYBh4=; b=vgWgHAn6YIln/UhTR3BirbJ+NWUoR/SJjxPsoD2LWGpUuXh4ThfyD/2Czt9l8Sh6xsh4rz 9j4WVwYeD6AuQ90CRqWj2z3zh83XzU6O8CoY8HXKP0k3emYxOfDQ7I1Qm7P1Cz7bxEo90B g0xW/o0PoqrMBhcsZIBIRKhKgeOwMuN6b8rHRE17dsOIctU63MsnSAAqEjudXIcDA8+cx6 P2iKyhWGG8XtBC/LXgzbPlwtMpm7ZctDD1YK+BGCVoZyC1xBbzHs8CxVfQDilDL7KyytZt wjxyqwC1c90NHA0EsEFUuQYwFGk/E0FNSakDwqJwf2vBEVuKM3GMA1mAcWFEXA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1730227536; a=rsa-sha256; cv=none; b=qqnGJU7GIdP/xo2aAxCX32JVwjHA8xdxLqS2YtHa6MgWi9fv0ayFBTL9PYue43XiMFgVA+ 8p9VmA7XZsNtr9Mi9Cml16zxIA0YVkYNmkdeE2KhzmF3Dhc22wdZMzdn2L6G2PEuowcjGS H0OcTVdaVdUDuv0f+5oWvl5BMqqOay/G9/TVpzkvFpWSrwrX+aaXuc0nyC17rTFA+Nq++s jkn/I/Gl1UxdM6JyUdo40c0mNmr/yHy95qQdJ3BV0xb+SbhxPg3kTznf5PGvprnR9oseRs mpBzZMaCEUEO/+o0Bi1ubjb2H9+H1Kj87tVPJMd5/FVzlti156agxwyKcxOefg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4XdK2S64zXzbLX; Tue, 29 Oct 2024 18:45:36 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 49TIjaTN017068; Tue, 29 Oct 2024 18:45:36 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 49TIja2c017065; Tue, 29 Oct 2024 18:45:36 GMT (envelope-from git) Date: Tue, 29 Oct 2024 18:45:36 GMT Message-Id: <202410291845.49TIja2c017065@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Ed Maste Subject: git: fcd9a2d8a5bd - releng/14.1 - bhyve/nvme: Fix Infinite loop in queue processing List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: emaste X-Git-Repository: src X-Git-Refname: refs/heads/releng/14.1 X-Git-Reftype: branch X-Git-Commit: fcd9a2d8a5bd6a76a70ea49fee8af8a73e2ce85a Auto-Submitted: auto-generated The branch releng/14.1 has been updated by emaste: URL: https://cgit.FreeBSD.org/src/commit/?id=fcd9a2d8a5bd6a76a70ea49fee8af8a73e2ce85a commit fcd9a2d8a5bd6a76a70ea49fee8af8a73e2ce85a Author: Chuck Tuffli AuthorDate: 2024-10-13 13:58:48 +0000 Commit: Ed Maste CommitDate: 2024-10-29 18:44:00 +0000 bhyve/nvme: Fix Infinite loop in queue processing In the functions pci_nvme_handle_admin_cmd and pci_nvme_handle_io_cmd infinite loops are possible in the bhyve process if the sq->tail value is greater than sq->size. An attacker could overload the host CPU. Fix is to validate that doorbell values: - Are for a valid (i.e., created) queue - Are not the same as the previous value - Fit within the available capacity The emulation will generate an Asynchronous Event Notification (Invalid Doorbell or Invalid Doorbell Value) if enabled and ignore the doorbell update. While in the neighborhood, remove a redundant bounds check. Reported by: Synacktiv MFC after: 1 week Security: HYP-14 Security: FreeBSD-SA-24:17.bhyve Approved by: so Sponsored by: Alpha-Omega Project Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D46064 (cherry picked from commit 5374b9e146811757540e35553a7712c5b9b29239) (cherry picked from commit 86ba5941b132c73476a2a1b76ae53902a027b81c) --- usr.sbin/bhyve/pci_nvme.c | 81 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 8 deletions(-) diff --git a/usr.sbin/bhyve/pci_nvme.c b/usr.sbin/bhyve/pci_nvme.c index a2e52ece7675..362ed09523fd 100644 --- a/usr.sbin/bhyve/pci_nvme.c +++ b/usr.sbin/bhyve/pci_nvme.c @@ -265,6 +265,17 @@ struct pci_nvme_aer { uint16_t cid; /* Command ID of the submitted AER */ }; +/** Asynchronous Event Information - Error */ +typedef enum { + PCI_NVME_AEI_ERROR_INVALID_DB, + PCI_NVME_AEI_ERROR_INVALID_DB_VALUE, + PCI_NVME_AEI_ERROR_DIAG_FAILURE, + PCI_NVME_AEI_ERROR_PERSISTANT_ERR, + PCI_NVME_AEI_ERROR_TRANSIENT_ERR, + PCI_NVME_AEI_ERROR_FIRMWARE_LOAD_ERR, + PCI_NVME_AEI_ERROR_MAX, +} pci_nvme_async_event_info_error; + /** Asynchronous Event Information - Notice */ typedef enum { PCI_NVME_AEI_NOTICE_NS_ATTR_CHANGED = 0, @@ -2789,6 +2800,38 @@ complete: pthread_mutex_unlock(&sq->mtx); } +/* + * Check for invalid doorbell write values + * See NVM Express Base Specification, revision 2.0 + * "Asynchronous Event Information - Error Status" for details + */ +static bool +pci_nvme_sq_doorbell_valid(struct nvme_submission_queue *sq, uint64_t value) +{ + uint64_t capacity; + + /* + * Queue empty : head == tail + * Queue full : head is one more than tail accounting for wrap + * Therefore, can never have more than (size - 1) entries + */ + if (sq->head == sq->tail) + capacity = sq->size - 1; + else if (sq->head > sq->tail) + capacity = sq->size - (sq->head - sq->tail) - 1; + else + capacity = sq->tail - sq->head - 1; + + if ((value == sq->tail) || /* same as previous */ + (value > capacity)) { /* exceeds queue capacity */ + EPRINTLN("%s: SQ size=%u head=%u tail=%u capacity=%lu value=%lu", + __func__, sq->size, sq->head, sq->tail, capacity, value); + return false; + } + + return true; +} + static void pci_nvme_handle_doorbell(struct pci_nvme_softc* sc, uint64_t idx, int is_sq, uint64_t value) @@ -2801,22 +2844,34 @@ pci_nvme_handle_doorbell(struct pci_nvme_softc* sc, WPRINTF("%s queue index %lu overflow from " "guest (max %u)", __func__, idx, sc->num_squeues); + pci_nvme_aen_post(sc, PCI_NVME_AE_TYPE_ERROR, + PCI_NVME_AEI_ERROR_INVALID_DB); + return; + } + + if (sc->submit_queues[idx].qbase == NULL) { + WPRINTF("%s write to SQ %lu before created", __func__, + idx); + pci_nvme_aen_post(sc, PCI_NVME_AE_TYPE_ERROR, + PCI_NVME_AEI_ERROR_INVALID_DB); + return; + } + + if (!pci_nvme_sq_doorbell_valid(&sc->submit_queues[idx], value)) { + EPRINTLN("%s write to SQ %lu of %lu invalid", __func__, + idx, value); + pci_nvme_aen_post(sc, PCI_NVME_AE_TYPE_ERROR, + PCI_NVME_AEI_ERROR_INVALID_DB_VALUE); return; } atomic_store_short(&sc->submit_queues[idx].tail, (uint16_t)value); - if (idx == 0) { + if (idx == 0) pci_nvme_handle_admin_cmd(sc, value); - } else { + else { /* submission queue; handle new entries in SQ */ - if (idx > sc->num_squeues) { - WPRINTF("%s SQ index %lu overflow from " - "guest (max %u)", - __func__, idx, sc->num_squeues); - return; - } pci_nvme_handle_io_cmd(sc, (uint16_t)idx); } } else { @@ -2824,6 +2879,16 @@ pci_nvme_handle_doorbell(struct pci_nvme_softc* sc, WPRINTF("%s queue index %lu overflow from " "guest (max %u)", __func__, idx, sc->num_cqueues); + pci_nvme_aen_post(sc, PCI_NVME_AE_TYPE_ERROR, + PCI_NVME_AEI_ERROR_INVALID_DB); + return; + } + + if (sc->compl_queues[idx].qbase == NULL) { + WPRINTF("%s write to CQ %lu before created", __func__, + idx); + pci_nvme_aen_post(sc, PCI_NVME_AE_TYPE_ERROR, + PCI_NVME_AEI_ERROR_INVALID_DB); return; }