* [PATCH v2 0/2] hw/usb/hcd-ehci: Fix Coverity CID 1685236 and check DMA errors
@ 2026-08-17 2:36 Jamin Lin
2026-08-17 2:36 ` [PATCH v2 1/2] hw/usb/hcd-ehci: Handle get_dwords() failures in async writeback Jamin Lin
2026-08-17 2:36 ` [PATCH v2 2/2] hw/usb/hcd-ehci: Check for DMA errors in get_dwords()/put_dwords() Jamin Lin
0 siblings, 2 replies; 5+ messages in thread
From: Jamin Lin @ 2026-08-17 2:36 UTC (permalink / raw)
To: clg@redhat.com, pbonzini@redhat.com, peter.maydell@linaro.org,
philmd@mailo.com, open list:All patches CC here
Cc: Jamin Lin, Troy Lee
v1:
1. Fix Fix Coverity CID 1685236
v2:
1. Drops the dead NULL test and checks the actual accesses instead, and makes put_dwords() return void
since no caller can act on a failed writeback.
Jamin Lin (2):
hw/usb/hcd-ehci: Handle get_dwords() failures in async writeback
hw/usb/hcd-ehci: Check for DMA errors in get_dwords()/put_dwords()
hw/usb/hcd-ehci.c | 48 +++++++++++++++++++++--------------------------
1 file changed, 21 insertions(+), 27 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/2] hw/usb/hcd-ehci: Handle get_dwords() failures in async writeback
2026-08-17 2:36 [PATCH v2 0/2] hw/usb/hcd-ehci: Fix Coverity CID 1685236 and check DMA errors Jamin Lin
@ 2026-08-17 2:36 ` Jamin Lin
2026-08-17 2:36 ` [PATCH v2 2/2] hw/usb/hcd-ehci: Check for DMA errors in get_dwords()/put_dwords() Jamin Lin
1 sibling, 0 replies; 5+ messages in thread
From: Jamin Lin @ 2026-08-17 2:36 UTC (permalink / raw)
To: clg@redhat.com, pbonzini@redhat.com, peter.maydell@linaro.org,
philmd@mailo.com, open list:All patches CC here
Cc: Jamin Lin, Troy Lee, Philippe Mathieu-Daudé
Coverity reports that ehci_writeback_async_complete_packet() ignores
the return value of get_dwords() when reading the QH and qTD.
Handle read failures in the same way as QH and qTD verification
failures by freeing the packet and returning early.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
Resolves: Coverity CID 1685236
Fixes: 2b3de6ada5d ("ehci: writeback_async_complete_packet: verify qh and qtd")
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
hw/usb/hcd-ehci.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 451a918e9f..d43951975a 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -533,11 +533,11 @@ static void ehci_writeback_async_complete_packet(EHCIPacket *p)
/* Verify the qh + qtd, like we do when going through fetchqh & fetchqtd */
memset(&qh, 0, sizeof(qh));
memset(&qtd, 0, sizeof(qtd));
- get_dwords(q->ehci, NLPTR_GET(q->qhaddr),
- (uint32_t *) &qh, ehci_qh_dwords(q->ehci));
- get_dwords(q->ehci, NLPTR_GET(q->qtdaddr),
- (uint32_t *) &qtd, ehci_qtd_dwords(q->ehci));
- if (!ehci_verify_qh(q, &qh) || !ehci_verify_qtd(p, &qtd)) {
+ if (get_dwords(q->ehci, NLPTR_GET(q->qhaddr),
+ (uint32_t *) &qh, ehci_qh_dwords(q->ehci)) < 0 ||
+ get_dwords(q->ehci, NLPTR_GET(q->qtdaddr),
+ (uint32_t *) &qtd, ehci_qtd_dwords(q->ehci)) < 0 ||
+ !ehci_verify_qh(q, &qh) || !ehci_verify_qtd(p, &qtd)) {
p->async = EHCI_ASYNC_INITIALIZED;
ehci_free_packet(p);
return;
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 2/2] hw/usb/hcd-ehci: Check for DMA errors in get_dwords()/put_dwords()
2026-08-17 2:36 [PATCH v2 0/2] hw/usb/hcd-ehci: Fix Coverity CID 1685236 and check DMA errors Jamin Lin
2026-08-17 2:36 ` [PATCH v2 1/2] hw/usb/hcd-ehci: Handle get_dwords() failures in async writeback Jamin Lin
@ 2026-08-17 2:36 ` Jamin Lin
2026-08-17 4:17 ` Philippe Mathieu-Daudé
1 sibling, 1 reply; 5+ messages in thread
From: Jamin Lin @ 2026-08-17 2:36 UTC (permalink / raw)
To: clg@redhat.com, pbonzini@redhat.com, peter.maydell@linaro.org,
philmd@mailo.com, open list:All patches CC here
Cc: Jamin Lin, Troy Lee
get_dwords() and put_dwords() return -1 when ehci->as is NULL, but that
can no longer happen. The sysbus variants set it in instance_init
(ehci_sysbus_init()), the PCI variant sets it in realize
(usb_ehci_pci_realize()), and usb_ehci_pci_write_config() only switches
between the bus master address space and address_space_memory.
Meanwhile the results of dma_memory_read() and dma_memory_write() are
ignored, so a failed guest memory access is silently treated as success.
Drop the dead NULL test and check the MemTxResult of each access
instead, so that the existing -1 error path reports real DMA errors:
raise USBSTS_HSE, clear USBCMD_RUNSTOP and stop processing the
descriptor, as the NULL path used to do. All 11 get_dwords() callers
already check the return value.
put_dwords() now returns void: none of its four callers (ehci_flush_qh(),
ehci_state_fetchitd() and twice in ehci_state_writeback()) looks at the
status.
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
hw/usb/hcd-ehci.c | 38 ++++++++++++++++----------------------
1 file changed, 16 insertions(+), 22 deletions(-)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index d43951975a..daab5783bc 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -421,16 +421,14 @@ static inline int get_dwords(EHCIState *ehci, uint64_t addr,
{
int i;
- if (!ehci->as) {
- ehci_raise_irq(ehci, USBSTS_HSE);
- ehci->usbcmd &= ~USBCMD_RUNSTOP;
- trace_usb_ehci_dma_error();
- return -1;
- }
-
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- dma_memory_read(ehci->as, addr, buf, sizeof(*buf),
- MEMTXATTRS_UNSPECIFIED);
+ if (dma_memory_read(ehci->as, addr, buf, sizeof(*buf),
+ MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
+ ehci_raise_irq(ehci, USBSTS_HSE);
+ ehci->usbcmd &= ~USBCMD_RUNSTOP;
+ trace_usb_ehci_dma_error();
+ return -1;
+ }
*buf = le32_to_cpu(*buf);
}
@@ -438,25 +436,21 @@ static inline int get_dwords(EHCIState *ehci, uint64_t addr,
}
/* Put an array of dwords in to main memory */
-static inline int put_dwords(EHCIState *ehci, uint64_t addr,
- uint32_t *buf, int num)
+static inline void put_dwords(EHCIState *ehci, uint64_t addr,
+ uint32_t *buf, int num)
{
int i;
- if (!ehci->as) {
- ehci_raise_irq(ehci, USBSTS_HSE);
- ehci->usbcmd &= ~USBCMD_RUNSTOP;
- trace_usb_ehci_dma_error();
- return -1;
- }
-
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
uint32_t tmp = cpu_to_le32(*buf);
- dma_memory_write(ehci->as, addr, &tmp, sizeof(tmp),
- MEMTXATTRS_UNSPECIFIED);
+ if (dma_memory_write(ehci->as, addr, &tmp, sizeof(tmp),
+ MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
+ ehci_raise_irq(ehci, USBSTS_HSE);
+ ehci->usbcmd &= ~USBCMD_RUNSTOP;
+ trace_usb_ehci_dma_error();
+ return;
+ }
}
-
- return num;
}
static int ehci_get_pid(EHCIqtd *qtd)
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 2/2] hw/usb/hcd-ehci: Check for DMA errors in get_dwords()/put_dwords()
2026-08-17 2:36 ` [PATCH v2 2/2] hw/usb/hcd-ehci: Check for DMA errors in get_dwords()/put_dwords() Jamin Lin
@ 2026-08-17 4:17 ` Philippe Mathieu-Daudé
2026-08-17 5:13 ` Jamin Lin
0 siblings, 1 reply; 5+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-08-17 4:17 UTC (permalink / raw)
To: Jamin Lin, clg@redhat.com, pbonzini@redhat.com,
peter.maydell@linaro.org, philmd@mailo.com,
open list:All patches CC here
Cc: Troy Lee
On 17/8/26 04:36, Jamin Lin wrote:
> get_dwords() and put_dwords() return -1 when ehci->as is NULL, but that
> can no longer happen. The sysbus variants set it in instance_init
> (ehci_sysbus_init()), the PCI variant sets it in realize
> (usb_ehci_pci_realize()), and usb_ehci_pci_write_config() only switches
> between the bus master address space and address_space_memory.
>
> Meanwhile the results of dma_memory_read() and dma_memory_write() are
> ignored, so a failed guest memory access is silently treated as success.
>
> Drop the dead NULL test and check the MemTxResult of each access
> instead, so that the existing -1 error path reports real DMA errors:
> raise USBSTS_HSE, clear USBCMD_RUNSTOP and stop processing the
> descriptor, as the NULL path used to do. All 11 get_dwords() callers
> already check the return value.
>
> put_dwords() now returns void: none of its four callers (ehci_flush_qh(),
> ehci_state_fetchitd() and twice in ehci_state_writeback()) looks at the
> status.
>
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
> Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> ---
> hw/usb/hcd-ehci.c | 38 ++++++++++++++++----------------------
> 1 file changed, 16 insertions(+), 22 deletions(-)
>
> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
> index d43951975a..daab5783bc 100644
> --- a/hw/usb/hcd-ehci.c
> +++ b/hw/usb/hcd-ehci.c
> @@ -421,16 +421,14 @@ static inline int get_dwords(EHCIState *ehci, uint64_t addr,
> {
> int i;
>
> - if (!ehci->as) {
> - ehci_raise_irq(ehci, USBSTS_HSE);
> - ehci->usbcmd &= ~USBCMD_RUNSTOP;
> - trace_usb_ehci_dma_error();
> - return -1;
> - }
> -
> for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
> - dma_memory_read(ehci->as, addr, buf, sizeof(*buf),
> - MEMTXATTRS_UNSPECIFIED);
> + if (dma_memory_read(ehci->as, addr, buf, sizeof(*buf),
> + MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
> + ehci_raise_irq(ehci, USBSTS_HSE);
> + ehci->usbcmd &= ~USBCMD_RUNSTOP;
> + trace_usb_ehci_dma_error();
> + return -1;
> + }
> *buf = le32_to_cpu(*buf);
> }
Maybe reorder before previous patch?
Note, for EHCI get_dwords() is only used as returning a boolean,
which would match with your conversion of put_dwords to void. While
the change involves some code churn, the result would be clearer
IMHO. Anyway can be done later.
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* RE: [PATCH v2 2/2] hw/usb/hcd-ehci: Check for DMA errors in get_dwords()/put_dwords()
2026-08-17 4:17 ` Philippe Mathieu-Daudé
@ 2026-08-17 5:13 ` Jamin Lin
0 siblings, 0 replies; 5+ messages in thread
From: Jamin Lin @ 2026-08-17 5:13 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, clg@redhat.com, pbonzini@redhat.com,
peter.maydell@linaro.org, philmd@mailo.com,
open list:All patches CC here
Cc: Troy Lee
Hi Philippe
> Subject: Re: [PATCH v2 2/2] hw/usb/hcd-ehci: Check for DMA errors in
> get_dwords()/put_dwords()
>
> On 17/8/26 04:36, Jamin Lin wrote:
> > get_dwords() and put_dwords() return -1 when ehci->as is NULL, but
> > that can no longer happen. The sysbus variants set it in instance_init
> > (ehci_sysbus_init()), the PCI variant sets it in realize
> > (usb_ehci_pci_realize()), and usb_ehci_pci_write_config() only
> > switches between the bus master address space and
> address_space_memory.
> >
> > Meanwhile the results of dma_memory_read() and dma_memory_write()
> are
> > ignored, so a failed guest memory access is silently treated as success.
> >
> > Drop the dead NULL test and check the MemTxResult of each access
> > instead, so that the existing -1 error path reports real DMA errors:
> > raise USBSTS_HSE, clear USBCMD_RUNSTOP and stop processing the
> > descriptor, as the NULL path used to do. All 11 get_dwords() callers
> > already check the return value.
> >
> > put_dwords() now returns void: none of its four callers
> > (ehci_flush_qh(),
> > ehci_state_fetchitd() and twice in ehci_state_writeback()) looks at
> > the status.
> >
>
> Suggested-by: Peter Maydell <peter.maydell@linaro.org>
>
> > Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
> > ---
> > hw/usb/hcd-ehci.c | 38 ++++++++++++++++----------------------
> > 1 file changed, 16 insertions(+), 22 deletions(-)
> >
> > diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index
> > d43951975a..daab5783bc 100644
> > --- a/hw/usb/hcd-ehci.c
> > +++ b/hw/usb/hcd-ehci.c
> > @@ -421,16 +421,14 @@ static inline int get_dwords(EHCIState *ehci,
> uint64_t addr,
> > {
> > int i;
> >
> > - if (!ehci->as) {
> > - ehci_raise_irq(ehci, USBSTS_HSE);
> > - ehci->usbcmd &= ~USBCMD_RUNSTOP;
> > - trace_usb_ehci_dma_error();
> > - return -1;
> > - }
> > -
> > for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
> > - dma_memory_read(ehci->as, addr, buf, sizeof(*buf),
> > - MEMTXATTRS_UNSPECIFIED);
> > + if (dma_memory_read(ehci->as, addr, buf, sizeof(*buf),
> > + MEMTXATTRS_UNSPECIFIED) !=
> MEMTX_OK) {
> > + ehci_raise_irq(ehci, USBSTS_HSE);
> > + ehci->usbcmd &= ~USBCMD_RUNSTOP;
> > + trace_usb_ehci_dma_error();
> > + return -1;
> > + }
> > *buf = le32_to_cpu(*buf);
> > }
>
> Maybe reorder before previous patch?
>
Will resend v3.
> Note, for EHCI get_dwords() is only used as returning a boolean, which would
> match with your conversion of put_dwords to void. While the change involves
> some code churn, the result would be clearer IMHO. Anyway can be done later.
>
Will add new patch in v3 and change get_dwords return type to a boolean.
Thanks,
Jamin
> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-17 5:14 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-17 2:36 [PATCH v2 0/2] hw/usb/hcd-ehci: Fix Coverity CID 1685236 and check DMA errors Jamin Lin
2026-08-17 2:36 ` [PATCH v2 1/2] hw/usb/hcd-ehci: Handle get_dwords() failures in async writeback Jamin Lin
2026-08-17 2:36 ` [PATCH v2 2/2] hw/usb/hcd-ehci: Check for DMA errors in get_dwords()/put_dwords() Jamin Lin
2026-08-17 4:17 ` Philippe Mathieu-Daudé
2026-08-17 5:13 ` Jamin Lin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.