Re: [PATCH] hw/net/vmxnet3: Do not abort if guest provides bad interrupt numbers
Philippe Mathieu-Daudé <[email protected]> Fri, 31 Jul 2026 08:03:04 +0200
| Newsgroups | org.nongnu.qemu-trivial,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
Hi Thomas, On 30/7/26 16:39, Thomas Huth wrote: > From: Thomas Huth <[email protected]> > > vmxnet3_validate_interrupts() currently aborts via hw_error() if > the guest provided bad interrupt numbers. This should not happen, > QEMU should rather refuse to activate the device in this case instead. > Thus propagate the error to the callers to handle it more gracefully > there. > > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/539 > Signed-off-by: Thomas Huth <[email protected]> > --- > hw/net/vmxnet3.c | 35 +++++++++++++++++++++++++++-------- > 1 file changed, 27 insertions(+), 8 deletions(-) > > diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c > index 8569484b2f2..1c5d1d740cc 100644 > --- a/hw/net/vmxnet3.c > +++ b/hw/net/vmxnet3.c > @@ -1336,32 +1336,46 @@ static bool vmxnet3_verify_intx(VMXNET3State *s, int intx) > || intx == pci_get_byte(s->parent_obj.config + PCI_INTERRUPT_PIN) - 1; > } > > -static void vmxnet3_validate_interrupt_idx(bool is_msix, int idx) > +static bool vmxnet3_validate_irq_idx(const char *type, bool is_msix, int idx) > { > int max_ints = is_msix ? VMXNET3_MAX_INTRS : VMXNET3_MAX_NMSIX_INTRS; > + > if (idx >= max_ints) { > - hw_error("Bad interrupt index: %d\n", idx); > + qemu_log_mask(LOG_GUEST_ERROR, > + "vmxnet3: Bad %s queue interrupt index: %d\n", > + type, idx); > + return false; > } > + > + return true; > } > > -static void vmxnet3_validate_interrupts(VMXNET3State *s) > +static bool vmxnet3_validate_interrupts(VMXNET3State *s) > { > int i; > > VMW_CFPRN("Verifying event interrupt index (%d)", s->event_int_idx); > - vmxnet3_validate_interrupt_idx(s->msix_used, s->event_int_idx); > + if (!vmxnet3_validate_irq_idx("event", s->msix_used, s->event_int_idx)) { > + return false; > + } > > for (i = 0; i < s->txq_num; i++) { > int idx = s->txq_descr[i].intr_idx; > VMW_CFPRN("Verifying TX queue %d interrupt index (%d)", i, idx); > - vmxnet3_validate_interrupt_idx(s->msix_used, idx); > + if (!vmxnet3_validate_irq_idx("TX", s->msix_used, idx)) { > + return false; > + } > } > > for (i = 0; i < s->rxq_num; i++) { > int idx = s->rxq_descr[i].intr_idx; > VMW_CFPRN("Verifying RX queue %d interrupt index (%d)", i, idx); > - vmxnet3_validate_interrupt_idx(s->msix_used, idx); > + if (!vmxnet3_validate_irq_idx("RX", s->msix_used, idx)) { > + return false; > + } > } > + > + return true; > } > > static bool vmxnet3_validate_queues(VMXNET3State *s) > @@ -1554,7 +1568,10 @@ static void vmxnet3_activate_device(VMXNET3State *s) > sizeof(s->rxq_descr[i].rxq_stats)); > } > > - vmxnet3_validate_interrupts(s); > + if (!vmxnet3_validate_interrupts(s)) { > + vmxnet3_reset(s); > + return; We definitively want to return here to not set s->device_active, but calling vmxnet3_reset() in the middle of a command handler is surprising. Maybe call it in the caller? -- >8 -- @@ -1554,7 +1554,9 @@ static void vmxnet3_activate_device(VMXNET3State *s) sizeof(s->rxq_descr[i].rxq_stats)); } - vmxnet3_validate_interrupts(s); + if (!vmxnet3_validate_interrupts(s)) { + return false; + } /* Make sure everything is in place before device activation */ smp_wmb(); @@ -1584,7 +1586,9 @@ static void vmxnet3_handle_command(VMXNET3State *s, uint64_t cmd) case VMXNET3_CMD_ACTIVATE_DEV: VMW_CBPRN("Set: Activating vmxnet3 device"); - vmxnet3_activate_device(s); + if (!vmxnet3_activate_device(s)) { + vmxnet3_reset(s); + } break; case VMXNET3_CMD_UPDATE_RX_MODE: --- Regardless this patch fixes what it aims to, and -- while I don't have much knowledge of this device -- it looks reasonable. Reviewed-by: Philippe Mathieu-Daudé <[email protected]> > + } > > /* Make sure everything is in place before device activation */ > smp_wmb(); > @@ -2392,7 +2409,9 @@ static int vmxnet3_post_load(void *opaque, int version_id) > if (!vmxnet3_validate_queues(s)) { > return -1; > } > - vmxnet3_validate_interrupts(s); > + if (!vmxnet3_validate_interrupts(s)) { > + return -1; > + } > > return 0; > }