git: f4d953bea740 - main - bhyve: Do not panic on invalid input in HDA emulation
Christos Margiolis <[email protected]>
| Newsgroups | gmane.os.freebsd.devel.cvs.src |
|---|---|
| Message-ID | <6a899acb.337c3.5cf69274__25557.9528909706$1787402984$gmane$org@gitrepo.freebsd.org> |
The branch main has been updated by christos: URL: https://cgit.FreeBSD.org/src/commit/?id=f4d953bea74091874f019e3a2c4902dd013ee739 commit f4d953bea74091874f019e3a2c4902dd013ee739 Author: Christos Margiolis <[email protected]> AuthorDate: 2026-08-22 12:48:32 +0000 Commit: Christos Margiolis <[email protected]> CommitDate: 2026-08-22 12:48:32 +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 --- 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); } } }