dorimanx/Dorimanx-SG2-I9100-Kernel — pull request #34 by lwi (2014-10-30 21:31:09+00:00)
Title: otg: when removing ED from readyQ also set flag

The driver keeps track of the "is this endpoint in the list" state with
the redundant flag ".is_in_transfer_ready_q". It should therefore always
be sync with the .next and .prev of the readyq_list list:

struct ed *ed;
otg_list_head *qlist = (typeof qlist) ed->readyq_list;

(qlist->prev == LIST_POISON2 || qlist->next == LIST_POISON1)
== !ed->ed_status.is_in_transfer_ready_q;

Should both properties be not in sync, bad things can happen. All code
paths in driver rely on the flag and then call list operations. If the
flag suggests the entry is in the list, otg_list_pop () will be called.
When the entry however is not in the list, the members .prev and .next
are poisoned and an attempt to do list operations on them results into a
NULL (or rather an invalid address which is the poison) pointer
dereference. Such a fault would then trigger a kernel panic and the
device rebooting.
In real life this happens when disconnecting USB devices frequently,
especially when in operation (transfering data while detaching).

While in most positions in the code, it was taken care to keep both
properties, the flag and the list entry state, consistent, one position
was left out, which is addressed with this patch.
Extensive testing shows that the device would crash easily and in a
reproducable manner without the patch but does not show any faults with
the patch applied.

This patch is also due to inclusion in CyanogenMod:
http://review.cyanogenmod.org/#/c/75836/