git: f4d953bea740 - main - bhyve: Do not panic on invalid input in HDA emulation
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 22 Aug 2026 12:49:15 UTC
The branch main has been updated by christos:
URL: https://cgit.FreeBSD.org/src/commit/?id=f4d953bea74091874f019e3a2c4902dd013ee739
commit f4d953bea74091874f019e3a2c4902dd013ee739
Author: Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2026-08-22 12:48:32 +0000
Commit: Christos Margiolis <christos@FreeBSD.org>
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);
}
}
}