On Fri, Jun 01, 2012 at 10:06:23AM +0200, Takashi Iwai wrote:
> xhci_free_tt_info() may access the invalid memory when it removes the
> last entry but the list is not empty.  Then tt_next reaches to the
> list head but it still tries to check the tt_info of that entry.
> 
> This patch fixes the bug and cleans up the messy code by rewriting
> with a simple list_for_each_entry_safe().
> 
> Cc: <[email protected]>
> Reviewed-by: Oliver Neukum <[email protected]>
> Signed-off-by: Takashi Iwai <[email protected]>

Ok, this looks correct.  I'll send it off to Greg in my next 3.5 pull
request.

Sarah Sharp

> ---
>  drivers/usb/host/xhci-mem.c |   38 +++++++++-----------------------------
>  1 file changed, 9 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
> index ec4338e..4e1da7f 100644
> --- a/drivers/usb/host/xhci-mem.c
> +++ b/drivers/usb/host/xhci-mem.c
> @@ -793,10 +793,9 @@ static void xhci_free_tt_info(struct xhci_hcd *xhci,
>               struct xhci_virt_device *virt_dev,
>               int slot_id)
>  {
> -     struct list_head *tt;
>       struct list_head *tt_list_head;
> -     struct list_head *tt_next;
> -     struct xhci_tt_bw_info *tt_info;
> +     struct xhci_tt_bw_info *tt_info, *next;
> +     bool slot_found = false;
>  
>       /* If the device never made it past the Set Address stage,
>        * it may not have the real_port set correctly.
> @@ -808,34 +807,15 @@ static void xhci_free_tt_info(struct xhci_hcd *xhci,
>       }
>  
>       tt_list_head = &(xhci->rh_bw[virt_dev->real_port - 1].tts);
> -     if (list_empty(tt_list_head))
> -             return;
> -
> -     list_for_each(tt, tt_list_head) {
> -             tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list);
> -             if (tt_info->slot_id == slot_id)
> +     list_for_each_entry_safe(tt_info, next, tt_list_head, tt_list) {
> +             /* Multi-TT hubs will have more than one entry */
> +             if (tt_info->slot_id == slot_id) {
> +                     slot_found = true;
> +                     list_del(&tt_info->tt_list);
> +                     kfree(tt_info);
> +             } else if (slot_found)
>                       break;
>       }
> -     /* Cautionary measure in case the hub was disconnected before we
> -      * stored the TT information.
> -      */
> -     if (tt_info->slot_id != slot_id)
> -             return;
> -
> -     tt_next = tt->next;
> -     tt_info = list_entry(tt, struct xhci_tt_bw_info,
> -                     tt_list);
> -     /* Multi-TT hubs will have more than one entry */
> -     do {
> -             list_del(tt);
> -             kfree(tt_info);
> -             tt = tt_next;
> -             if (list_empty(tt_list_head))
> -                     break;
> -             tt_next = tt->next;
> -             tt_info = list_entry(tt, struct xhci_tt_bw_info,
> -                             tt_list);
> -     } while (tt_info->slot_id == slot_id);
>  }
>  
>  int xhci_alloc_tt_info(struct xhci_hcd *xhci,
> -- 
> 1.7.9.2
> 
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to