The branch stable/15 has been updated by christos:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=3557da0355326ca1266d152c9df00a46bbb7ea92

commit 3557da0355326ca1266d152c9df00a46bbb7ea92
Author:     Christos Margiolis <[email protected]>
AuthorDate: 2026-08-22 12:48:32 +0000
Commit:     Christos Margiolis <[email protected]>
CommitDate: 2026-09-05 12:29:22 +0000

    bhyve: Do not panic on invalid input in HDA emulation
    
    The emulated HDA controller passed values taken from guest registers and
    from guest memory straight into assert(), so a guest could abort bhyve
    with values the emulation did not expect. Reject them instead.
    
    In case the guest asked to start something and it failed, clear the
    corresponding run/enable bit.
    
    PR:             256379, 256381, 256382, 256383, 256384, 256385, 256386, 
256498
    Sponsored by:   The FreeBSD Foundation
    MFC after:      2 weeks
    Reviewed by:    bnovkov, jhb
    Differential Revision:  https://reviews.freebsd.org/D59082
    
    (cherry picked from commit f4d953bea74091874f019e3a2c4902dd013ee739)
---
 usr.sbin/bhyve/pci_hda.c | 55 ++++++++++++++++++++++++++++++++----------------
 1 file changed, 37 insertions(+), 18 deletions(-)

diff --git a/usr.sbin/bhyve/pci_hda.c b/usr.sbin/bhyve/pci_hda.c
index 97d6264413e0..92e347f641d9 100644
--- a/usr.sbin/bhyve/pci_hda.c
+++ b/usr.sbin/bhyve/pci_hda.c
@@ -612,14 +612,20 @@ hda_stream_start(struct hda_softc *sc, uint8_t stream_ind)
        uint8_t strm = 0;
        uint8_t dir = 0;
 
-       assert(!st->run);
+       if (st->run) {
+               DPRINTF("Stream 0x%x is already running", stream_ind);
+               return (-1);
+       }
 
        lvi = hda_get_reg_by_offset(sc, off + HDAC_SDLVI);
        bdpl = hda_get_reg_by_offset(sc, off + HDAC_SDBDPL);
        bdpu = hda_get_reg_by_offset(sc, off + HDAC_SDBDPU);
 
+       if (lvi >= HDA_BDL_MAX_LEN) {
+               DPRINTF("Invalid LVI: 0x%x", lvi);
+               return (-1);
+       }
        bdl_cnt = lvi + 1;
-       assert(bdl_cnt <= HDA_BDL_MAX_LEN);
 
        bdl_paddr = bdpl | (bdpu << 32);
        bdl_vaddr = hda_dma_get_vaddr(sc, bdl_paddr,
@@ -637,7 +643,10 @@ hda_stream_start(struct hda_softc *sc, uint8_t stream_ind)
        bdle = (struct hda_bdle *)bdl_vaddr;
        for (size_t i = 0; i < bdl_cnt; i++, bdle++) {
                bdle_sz = bdle->len;
-               assert(!(bdle_sz % HDA_DMA_ACCESS_LEN));
+               if ((bdle_sz % HDA_DMA_ACCESS_LEN) != 0) {
+                       DPRINTF("Invalid BDLE length: 0x%x", bdle_sz);
+                       return (-1);
+               }
 
                bdle_addrl = bdle->addrl;
                bdle_addrh = bdle->addrh;
@@ -785,7 +794,6 @@ hda_corb_run(struct hda_softc *sc)
 {
        struct hda_codec_cmd_ctl *corb = &sc->corb;
        uint32_t verb = 0;
-       int err;
 
        corb->wp = hda_get_reg_by_offset(sc, HDAC_CORBWP);
        if (corb->wp >= corb->size) {
@@ -801,8 +809,8 @@ hda_corb_run(struct hda_softc *sc)
                verb = hda_dma_ld_dword((uint8_t *)corb->dma_vaddr +
                    HDA_CORB_ENTRY_LEN * corb->rp);
 
-               err = hda_send_command(sc, verb);
-               assert(!err);
+               if (hda_send_command(sc, verb) != 0)
+                       DPRINTF("Fail to send verb: 0x%x", verb);
        }
 
        hda_set_reg_by_offset(sc, HDAC_CORBRP, corb->rp);
@@ -928,13 +936,16 @@ static void
 hda_set_corbctl(struct hda_softc *sc, uint32_t offset, uint32_t old)
 {
        uint32_t value = hda_get_reg_by_offset(sc, offset);
-       int err;
        struct hda_codec_cmd_ctl *corb = NULL;
 
        if (value & HDAC_CORBCTL_CORBRUN) {
                if (!(old & HDAC_CORBCTL_CORBRUN)) {
-                       err = hda_corb_start(sc);
-                       assert(!err);
+                       if (hda_corb_start(sc) != 0) {
+                               DPRINTF("Fail to start CORB");
+                               hda_set_field_by_offset(sc, offset,
+                                   HDAC_CORBCTL_CORBRUN, 0);
+                               return;
+                       }
                }
        } else {
                corb = &sc->corb;
@@ -948,12 +959,15 @@ static void
 hda_set_rirbctl(struct hda_softc *sc, uint32_t offset, uint32_t old __unused)
 {
        uint32_t value = hda_get_reg_by_offset(sc, offset);
-       int err;
        struct hda_codec_cmd_ctl *rirb = NULL;
 
        if (value & HDAC_RIRBCTL_RIRBDMAEN) {
-               err = hda_rirb_start(sc);
-               assert(!err);
+               if (hda_rirb_start(sc) != 0) {
+                       DPRINTF("Fail to start RIRB");
+                       hda_set_field_by_offset(sc, offset,
+                           HDAC_RIRBCTL_RIRBDMAEN, 0);
+                       return;
+               }
        } else {
                rirb = &sc->rirb;
                memset(rirb, 0, sizeof(*rirb));
@@ -996,7 +1010,8 @@ hda_set_dpiblbase(struct hda_softc *sc, uint32_t offset, 
uint32_t old)
                        if (!sc->dma_pib_vaddr) {
                                DPRINTF("Fail to get the guest \
                                         virtual address");
-                               assert(0);
+                               hda_set_field_by_offset(sc, offset,
+                                   HDAC_DPLBASE_DPLBASE_DMAPBE, 0);
                        }
                } else {
                        DPRINTF("DMA Position In Buffer Reset");
@@ -1010,7 +1025,6 @@ hda_set_sdctl(struct hda_softc *sc, uint32_t offset, 
uint32_t old)
 {
        uint8_t stream_ind = hda_get_stream_by_offsets(offset, HDAC_SDCTL0);
        uint32_t value = hda_get_reg_by_offset(sc, offset);
-       int err;
 
        DPRINTF("stream_ind: 0x%x old: 0x%x value: 0x%x",
            stream_ind, old, value);
@@ -1021,11 +1035,16 @@ hda_set_sdctl(struct hda_softc *sc, uint32_t offset, 
uint32_t old)
 
        if ((value & HDAC_SDCTL_RUN) != (old & HDAC_SDCTL_RUN)) {
                if (value & HDAC_SDCTL_RUN) {
-                       err = hda_stream_start(sc, stream_ind);
-                       assert(!err);
+                       if (hda_stream_start(sc, stream_ind) != 0) {
+                               DPRINTF("Fail to start stream 0x%x",
+                                   stream_ind);
+                               hda_set_field_by_offset(sc, offset,
+                                   HDAC_SDCTL_RUN, 0);
+                       }
                } else {
-                       err = hda_stream_stop(sc, stream_ind);
-                       assert(!err);
+                       if (hda_stream_stop(sc, stream_ind) != 0)
+                               DPRINTF("Fail to stop stream 0x%x",
+                                   stream_ind);
                }
        }
 }

Reply via email to