Re: [PATCH] [RFC] EHCI: add to memory barrier to updating hw_next

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

 



On Fri, Jul 19, 2013 at 11:50 AM, Ming Lei <tom.leiming@xxxxxxxxx> wrote:
> On Thu, Jul 18, 2013 at 10:08 PM, Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote:
>> On Thu, 18 Jul 2013, Ming Lei wrote:
>>
>>> > I guess that HC could have a use-after-free problem like following situation.
>>> >
>>> > 1. A qtd which is not at the queue head should be removed in qh_completions().
>>> > 2. The last->hw_next become be pointing at the next qtd but the hw_next value is delayed in write-buffer.
>>> > 3. The qtd is removed in the list.
>>> > 4. The qtd is freed into DMA pool and re-allocated for another urb.
>>> > 5. HC try to process last->hw_next and it is pointing re-allocated qtd.
>>> >
>>> > What do you think about it? Is it possible?
>>>
>>> I understand it might not be possible because:  when 'stopped' is set, that
>>> said the HC might not advance the queue. But I don't understand why
>>> 'last->hw_next' is patched here under 'stopped' situation.
>>
>> It should not be possible.  When "stopped" is set, the QH gets unlinked
>> and relinked before it can start up again.  Relinking involves some
>> memory barriers, so the qTD will not be accessed again by the HC.
>>
>> last->hw_next gets patched because the qTD might belong to some URB in
>> the middle of the queue that is being unlinked.  The URBs before it and
>> after it will still be active, so the queue link has to be updated.
>
> 'stopped' is set under below situations:
>
>      - unlink over or shutdown
>      - halt
>      - short packet(URB_SHORT_NOT_OK)
>
> Looks EHCI won't advance the queue(qh) any more on above situations, so I
> think last->hw_next might not need patching.
>
>>
>>> Even the 'stopped' case may be seldom triggered, do you know under
>>> which condition the stopped is triggered in your problem?(stall, short read
>>> or others)
>>
>> I was going to ask the same question.  This particular piece of code
>> gets executed _only_ when an URB is unlinked.  Not during any other
>> kind of error.
>
> The code may run under 'halt' or short packet(URB_SHORT_NOT_OK) too.
> If Gioh's problem falls to these two situations, below patch might be helpful.
>
> Because the qh will be unlinked when there is fault in the endpoint(halt, short
> packet), maybe it is safer to complete these URBs after the qh becomes
> unlinked,  like what the blew patch does:
>
> diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
> index b637a65..6a65e0a 100644
> --- a/drivers/usb/host/ehci-q.c
> +++ b/drivers/usb/host/ehci-q.c
> @@ -454,6 +454,10 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
>                         }
>                 }
>
> +               /* complete URBs after unlinking */
> +               if (stopped && state != QH_STATE_IDLE)
> +                       goto exit;
> +
>                 /* unless we already know the urb's status, collect qtd status
>                  * and update count of bytes transferred.  in common short read
>                  * cases with only one data qtd (including control transfers),
> @@ -489,15 +493,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
>                         }
>                 }
>
> -               /* if we're removing something not at the queue head,
> -                * patch the hardware queue pointer.
> -                */
> -               if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
> -                       last = list_entry (qtd->qtd_list.prev,
> -                                       struct ehci_qtd, qtd_list);
> -                       last->hw_next = qtd->hw_next;
> -               }
> -
>                 /* remove qtd; it's recycled after possible urb completion */
>                 list_del (&qtd->qtd_list);
>                 last = qtd;
> @@ -520,7 +515,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
>
>                 /* Otherwise the caller must unlink the QH. */
>         }
> -
> + exit:
>         /* restore original state; caller must unlink or relink */
>         qh->qh_state = state;

Please ignore this email, and looks I understand this piece of code totally
wrong:  active URBs and its qtds should survive qh unlink & relink.

Sorry for the noise, :-(


Thanks,
-- 
Ming Lei
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux