From 06ed11d4159516c231e42b5fc669a5419331b37b Mon Sep 17 00:00:00 2001 From: Wu Liang feng Date: Mon, 18 Apr 2016 14:16:14 +0800 Subject: [PATCH] usb: gadget: composite: don't queue OS desc request if req length is invalid In OS descriptors handling, if ctrl->bRequestType is USB_RECIP_DEVICE and w_index != 0x4 or (w_value >> 8) is true, it will not reset req->length, but use the default value(-EOPNOTSUPP), and queue an OS desc request with an invalid req->length. It always happens on the platforms which use os_desc(for example: rk3366,rk3399), and cause kernel panic as follows(use dwc3 driver): Unable to handle kernel paging request at virtual address ffffffc0f7e00000 Internal error: Oops: 96000146 [#1] PREEMPT SMP PC is at __dma_clean_range+0x18/0x30 LR is at __swiotlb_map_page+0x50/0x64 Call trace: [] __dma_clean_range+0x18/0x30 [] usb_gadget_map_request+0x134/0x1b0 [] __dwc3_ep0_do_control_data+0x110/0x14c [] __dwc3_gadget_ep0_queue+0x198/0x1b8 [] dwc3_gadget_ep0_queue+0xc0/0xe8 [] composite_ep0_queue.constprop.14+0x34/0x98 [] composite_setup+0xf60/0x100c [] android_setup+0xd8/0x138 [] dwc3_ep0_delegate_req+0x34/0x50 [] dwc3_ep0_interrupt+0x5dc/0xb58 [] dwc3_thread_interrupt+0x15c/0xa24 With this patch, the gadget driver will not queue a request and return immediately if req->length is invalid. And the usb controller driver can handle the unsupport request correctly. Change-Id: I60270d7c12fa190a99cd1079880a2f7167e7af27 Signed-off-by: Wu Liang feng --- drivers/usb/gadget/composite.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index ffa2a682c04b..53499a7ddf45 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1766,14 +1766,19 @@ unknown: } break; } - req->length = value; - req->context = cdev; - req->zero = value < w_length; - value = composite_ep0_queue(cdev, req, GFP_ATOMIC); - if (value < 0) { - DBG(cdev, "ep_queue --> %d\n", value); - req->status = 0; - composite_setup_complete(gadget->ep0, req); + + if (value >= 0) { + req->length = value; + req->context = cdev; + req->zero = value < w_length; + value = composite_ep0_queue(cdev, req, + GFP_ATOMIC); + if (value < 0) { + DBG(cdev, "ep_queue --> %d\n", value); + req->status = 0; + composite_setup_complete(gadget->ep0, + req); + } } return value; } -- 2.34.1