lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <855b4621-fc40-4281-9e44-7a2ac861dd4b@linux.intel.com>
Date: Tue, 29 Jul 2025 18:00:36 +0300
From: Mathias Nyman <mathias.nyman@...ux.intel.com>
To: "WeitaoWang-oc@...oxin.com" <WeitaoWang-oc@...oxin.com>,
 gregkh@...uxfoundation.org, mathias.nyman@...el.com,
 linux-usb@...r.kernel.org, linux-kernel@...r.kernel.org
Cc: WeitaoWang@...oxin.com, wwt8723@....com, CobeChen@...oxin.com,
 stable@...r.kernel.org
Subject: Re: [PATCH v2] usb:xhci:Fix slot_id resource race conflict

On 29.7.2025 20.25, WeitaoWang-oc@...oxin.com wrote:
> On 2025/7/28 21:16, Mathias Nyman wrote:
>>
>> On 25.7.2025 21.51, Weitao Wang wrote:
>>> In such a scenario, device-A with slot_id equal to 1 is disconnecting
>>> while device-B is enumerating, device-B will fail to enumerate in the
>>> follow sequence.
>>>
>>> 1.[device-A] send disable slot command
>>> 2.[device-B] send enable slot command
>>> 3.[device-A] disable slot command completed and wakeup waiting thread
>>> 4.[device-B] enable slot command completed with slot_id equal to 1 and
>>> wakeup waiting thread
>>> 5.[device-B] driver check this slot_id was used by someone(device-A) in
>>> xhci_alloc_virt_device, this device fails to enumerate as this conflict
>>> 6.[device-A] xhci->devs[slot_id] set to NULL in xhci_free_virt_device
>>>
>>> To fix driver's slot_id resources conflict, let the xhci_free_virt_device
>>> functionm call in the interrupt handler when disable slot command success.
>>>
>>> Cc: stable@...r.kernel.org
>>> Fixes: 7faac1953ed1 ("xhci: avoid race between disable slot command and host runtime suspend")
>>> Signed-off-by: Weitao Wang <WeitaoWang-oc@...oxin.com>
>>
>> Nice catch, good to get this fixed.
>>
>> This however has the downside of doing a lot in interrupt context.
>>
>> what if we only clear some strategic pointers in the interrupt context,
>> and then do all the actual unmapping and endpoint ring segments freeing,
>> contexts freeing ,etc later?
>>
>> Pseudocode:
>>
>> xhci_handle_cmd_disable_slot(xhci, slot_id, comp_code)
>> {
>>      if (cmd_comp_code == COMP_SUCCESS) {
>>          xhci->dcbaa->dev_context_ptrs[slot_id] = 0;
>>          xhci->devs[slot_id] = NULL;
>>      }
>> }
>>
>> xhci_disable_and_free_slot(xhci, slot_id)
>> {
>>      struct xhci_virt_device *vdev = xhci->devs[slot_id];
>>
>>      xhci_disable_slot(xhci, slot_id);
>>      xhci_free_virt_device(xhci, vdev, slot_id);
>> }
>>
>> xhci_free_virt_device(xhci, vdev, slot_id)
>> {
>>      if (xhci->dcbaa->dev_context_ptrs[slot_id] == vdev->out_ctx->dma)
>>          xhci->dcbaa->dev_context_ptrs[slot_id] = 0;
>>
>>      // free and unmap things just like before
>>      ...
>>
>>      if (xhci->devs[slot_id] == vdev)
>>          xhci->devs[slot_id] = NULL;
>>
>>      kfee(vdev);
>> }
> 
> Hi Mathias,
> 
> Yes, your suggestion is a better revision, I made some modifications
> to the patch which is listed below. Please help to review again.
> Thanks for your help.
> 
> ---
>   drivers/usb/host/xhci-hub.c  |  3 +--
>   drivers/usb/host/xhci-mem.c  | 21 ++++++++++-----------
>   drivers/usb/host/xhci-ring.c |  9 +++++++--
>   drivers/usb/host/xhci.c      | 23 ++++++++++++++++-------
>   drivers/usb/host/xhci.h      |  3 ++-
>   5 files changed, 36 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
> index 92bb84f8132a..b3a59ce1b3f4 100644
> --- a/drivers/usb/host/xhci-hub.c
> +++ b/drivers/usb/host/xhci-hub.c
> @@ -704,8 +704,7 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci,
>           if (!xhci->devs[i])
>               continue;
> 
> -        retval = xhci_disable_slot(xhci, i);
> -        xhci_free_virt_device(xhci, i);
> +        retval = xhci_disable_and_free_slot(xhci, i);
>           if (retval)
>               xhci_err(xhci, "Failed to disable slot %d, %d. Enter test mode anyway\n",
>                    i, retval);
> diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
> index 6680afa4f596..fc4aca2e65bc 100644
> --- a/drivers/usb/host/xhci-mem.c
> +++ b/drivers/usb/host/xhci-mem.c
> @@ -865,21 +865,18 @@ int xhci_alloc_tt_info(struct xhci_hcd *xhci,
>    * will be manipulated by the configure endpoint, allocate device, or update
>    * hub functions while this function is removing the TT entries from the list.
>    */
> -void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
> +void xhci_free_virt_device(struct xhci_hcd *xhci, struct xhci_virt_device *dev,
> +        int slot_id)
>   {
> -    struct xhci_virt_device *dev;
>       int i;
>       int old_active_eps = 0;
> 
>       /* Slot ID 0 is reserved */
> -    if (slot_id == 0 || !xhci->devs[slot_id])
> +    if (slot_id == 0 || !dev)
>           return;
> 
> -    dev = xhci->devs[slot_id];
> -
> -    xhci->dcbaa->dev_context_ptrs[slot_id] = 0;
> -    if (!dev)
> -        return;
> +    if (xhci->dcbaa->dev_context_ptrs[slot_id] == dev->out_ctx->dma)

forgot that dev_context_ptrs[] values are stored as le64 while
out_ctx->dma  is in whatever cpu uses.

So above should be:
if (xhci->dcbaa->dev_context_ptrs[slot_id] == cpu_to_le64(dev->out_ctx->dma))

Otherwise it looks good to me

Thanks
Mathias


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ