lkml.org 
[lkml]   [2015]   [Feb]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 3.2 101/152] usb: gadget: udc: atmel: fix possible oops when unloading module
    3.2.67-rc1 review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Songjun Wu <songjun.wu@atmel.com>

    commit 5fb694f96e7c19e66b1c55124b98812e32e3efa5 upstream.

    When unloading the module 'g_hid.ko', the urb request will be dequeued and the
    completion routine will be excuted. If there is no urb packet, the urb request
    will not be added to the endpoint queue and the completion routine pointer in
    urb request is NULL.

    Accessing to this NULL function pointer will cause the Oops issue reported
    below.

    Add the code to check if the urb request is in the endpoint queue
    or not. If the urb request is not in the endpoint queue, a negative
    error code will be returned.

    Here is the Oops log:

    Unable to handle kernel NULL pointer dereference at virtual address 00000000
    pgd = dedf0000
    [00000000] *pgd=3ede5831, *pte=00000000, *ppte=00000000
    Internal error: Oops: 80000007 [#1] ARM
    Modules linked in: g_hid(-) usb_f_hid libcomposite
    CPU: 0 PID: 923 Comm: rmmod Not tainted 3.18.0+ #2
    Hardware name: Atmel SAMA5 (Device Tree)
    task: df6b1100 ti: dedf6000 task.ti: dedf6000
    PC is at 0x0
    LR is at usb_gadget_giveback_request+0xc/0x10
    pc : [<00000000>] lr : [<c02ace88>] psr: 60000093
    sp : dedf7eb0 ip : df572634 fp : 00000000
    r10: 00000000 r9 : df52e210 r8 : 60000013
    r7 : df6a9858 r6 : df52e210 r5 : df6a9858 r4 : df572600
    r3 : 00000000 r2 : ffffff98 r1 : df572600 r0 : df6a9868
    Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user
    Control: 10c53c7d Table: 3edf0059 DAC: 00000015
    Process rmmod (pid: 923, stack limit = 0xdedf6230)
    Stack: (0xdedf7eb0 to 0xdedf8000)
    7ea0: 00000000 c02adbbc df572580 deced608
    7ec0: df572600 df6a9868 df572634 c02aed3c df577c00 c01b8608 00000000 df6be27c
    7ee0: 00200200 00100100 bf0162f4 c000e544 dedf6000 00000000 00000000 bf010c00
    7f00: bf0162cc bf00159c 00000000 df572980 df52e218 00000001 df5729b8 bf0031d0
    [..]
    [<c02ace88>] (usb_gadget_giveback_request) from [<c02adbbc>] (request_complete+0x64/0x88)
    [<c02adbbc>] (request_complete) from [<c02aed3c>] (usba_ep_dequeue+0x70/0x128)
    [<c02aed3c>] (usba_ep_dequeue) from [<bf010c00>] (hidg_unbind+0x50/0x7c [usb_f_hid])
    [<bf010c00>] (hidg_unbind [usb_f_hid]) from [<bf00159c>] (remove_config.isra.6+0x98/0x9c [libcomposite])
    [<bf00159c>] (remove_config.isra.6 [libcomposite]) from [<bf0031d0>] (__composite_unbind+0x34/0x98 [libcomposite])
    [<bf0031d0>] (__composite_unbind [libcomposite]) from [<c02acee0>] (usb_gadget_remove_driver+0x50/0x78)
    [<c02acee0>] (usb_gadget_remove_driver) from [<c02ad570>] (usb_gadget_unregister_driver+0x64/0x94)
    [<c02ad570>] (usb_gadget_unregister_driver) from [<bf0160c0>] (hidg_cleanup+0x10/0x34 [g_hid])
    [<bf0160c0>] (hidg_cleanup [g_hid]) from [<c0056748>] (SyS_delete_module+0x118/0x19c)
    [<c0056748>] (SyS_delete_module) from [<c000e3c0>] (ret_fast_syscall+0x0/0x30)
    Code: bad PC value

    Signed-off-by: Songjun Wu <songjun.wu@atmel.com>
    [nicolas.ferre@atmel.com: reworked the commit message]
    Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
    Fixes: 914a3f3b3754 ("USB: add atmel_usba_udc driver")
    Signed-off-by: Felipe Balbi <balbi@ti.com>
    [bwh: Backported to 3.2: adjust filename]
    Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
    ---
    drivers/usb/gadget/atmel_usba_udc.c | 12 +++++++++++-
    1 file changed, 11 insertions(+), 1 deletion(-)

    --- a/drivers/usb/gadget/atmel_usba_udc.c
    +++ b/drivers/usb/gadget/atmel_usba_udc.c
    @@ -850,7 +850,7 @@ static int usba_ep_dequeue(struct usb_ep
    {
    struct usba_ep *ep = to_usba_ep(_ep);
    struct usba_udc *udc = ep->udc;
    - struct usba_request *req = to_usba_req(_req);
    + struct usba_request *req;
    unsigned long flags;
    u32 status;

    @@ -859,6 +859,16 @@ static int usba_ep_dequeue(struct usb_ep

    spin_lock_irqsave(&udc->lock, flags);

    + list_for_each_entry(req, &ep->queue, queue) {
    + if (&req->req == _req)
    + break;
    + }
    +
    + if (&req->req != _req) {
    + spin_unlock_irqrestore(&udc->lock, flags);
    + return -EINVAL;
    + }
    +
    if (req->using_dma) {
    /*
    * If this request is currently being transferred,


    \
     
     \ /
      Last update: 2015-02-17 03:41    [W:4.105 / U:0.760 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site