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