qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v2 for-7.1] hw/usb/hcd-xhci: Fix unbounded loop in xhci_ring_


From: Mauro Matteo Cascella
Subject: Re: [PATCH v2 for-7.1] hw/usb/hcd-xhci: Fix unbounded loop in xhci_ring_chain_length() (CVE-2020-14394)
Date: Fri, 5 Aug 2022 11:22:49 +0200

On Thu, Aug 4, 2022 at 3:13 PM Thomas Huth <thuth@redhat.com> wrote:
>
> The loop condition in xhci_ring_chain_length() is under control of
> the guest, and additionally the code does not check for failed DMA
> transfers (e.g. if reaching the end of the RAM), so the loop there
> could run for a very long time or even forever. Fix it by checking
> the return value of dma_memory_read() and by introducing a maximum
> loop length.
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/646
> Signed-off-by: Thomas Huth <thuth@redhat.com>
> ---
>  v2:
>  - Reworded subject and commit description
>  - Focus on xhci_ring_chain_length() since that's the only function
>    where an endless loop can currently occur. The other spots that
>    ignore the return value of dma_memory_read() should be fixed as
>    well later, but that's rather something for QEMU 7.2.
>  - Added an real limit for the loop, so that it also ends after a
>    while in case there are no DMA errors
>  - Use "return -1" instead of "return -length" since the latter
>    is somewhat weird (could be sometimes 0, sometimes negative)
>
>  hw/usb/hcd-xhci.c | 23 +++++++++++++++++++----
>  1 file changed, 19 insertions(+), 4 deletions(-)
>
> diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
> index 5a1ddf8c3e..b5669bc234 100644
> --- a/hw/usb/hcd-xhci.c
> +++ b/hw/usb/hcd-xhci.c
> @@ -21,6 +21,7 @@
>
>  #include "qemu/osdep.h"
>  #include "qemu/timer.h"
> +#include "qemu/log.h"
>  #include "qemu/module.h"
>  #include "qemu/queue.h"
>  #include "migration/vmstate.h"
> @@ -729,10 +730,14 @@ static int xhci_ring_chain_length(XHCIState *xhci, 
> const XHCIRing *ring)
>      bool control_td_set = 0;
>      uint32_t link_cnt = 0;
>
> -    while (1) {
> +    do {
>          TRBType type;
> -        dma_memory_read(xhci->as, dequeue, &trb, TRB_SIZE,
> -                        MEMTXATTRS_UNSPECIFIED);
> +        if (dma_memory_read(xhci->as, dequeue, &trb, TRB_SIZE,
> +                        MEMTXATTRS_UNSPECIFIED) != MEMTX_OK) {
> +            qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA memory access failed!\n",
> +                          __func__);
> +            return -1;
> +        }
>          le64_to_cpus(&trb.parameter);
>          le32_to_cpus(&trb.status);
>          le32_to_cpus(&trb.control);
> @@ -766,7 +771,17 @@ static int xhci_ring_chain_length(XHCIState *xhci, const 
> XHCIRing *ring)
>          if (!control_td_set && !(trb.control & TRB_TR_CH)) {
>              return length;
>          }
> -    }
> +
> +        /*
> +         * According to the xHCI spec, Transfer Ring segments should have
> +         * a maximum size of 64 kB (see chapter "6 Data Structures")
> +         */
> +    } while (length < TRB_LINK_LIMIT * 65536 / TRB_SIZE);
> +
> +    qemu_log_mask(LOG_GUEST_ERROR, "%s: exceeded maximum tranfer ring 
> size!\n",
> +                          __func__);
> +
> +    return -1;
>  }
>
>  static void xhci_er_reset(XHCIState *xhci, int v)
> --
> 2.31.1
>

Reviewed-by: Mauro Matteo Cascella <mcascell@redhat.com>

Thanks,
-- 
Mauro Matteo Cascella
Red Hat Product Security
PGP-Key ID: BB3410B0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]