ANDROID: usb: gadget: configfs: Protect composite_setup in a spinlock
In one of the SMMU faults (NULL Pointer derefernce) the following race condition was observed and func->interfaces_nums was being accessed for f_fs interface after it was unbinded resulting in a crash. Thread-1 Thread-2 ffs_func_req_match+0x68/0xc8 drain_workqueue+0xac gsi_unbind[usb_f_gsi]+0x64 purge_configs_funcs+0xb4 configfs_composite_unbind+0xac usb_gadget_remove_driver+0xac usb_gadget_unregister_driver+0xd8 gadget_dev_desc_UDC_store+0x114 android_setup+0x164/0x2a8 dwc3_ep0_inspect_setup+0x100/0x440 dwc3_ep0_interrupt+0xac/0x300 dwc3_process_event_entry+0x80/0x724 dwc3_process_event_buf+0x80/0x434 dwc3_thread_interrupt+0x60/0x124 irq_thread_fn+0x54/0xe4 irq_thread+0x3a4/0x6ec kthread+0x188/0x1ec ret_from_fork+0x10/0x20 The events happened in order are as follows: We got a setup packet for ffs interface and was passed to android setup callback from ep0.c. As part of the delegate request, the dwc->lock is released. At this instant a composition switch occurred and as per traces and crash dumps: 1. UDC Stop was done successfully. So run stop is set to '0' 2. Composite disconnect was done and ep disable for all ep's is done gadget->connected = FALSE 3. Async callbacks disabled dwc->aysnc_callbacks = FALSE 4. composite unbind is going on and the ffs interface in question is unbinded udc->driver != NULL (as per crash dump indicating that unbind is in progress) 5. Purge configs was ongoing because as per crash dumps: otg_desc[0] = NULL; cdev->os_desc_req->buf is not NULL (configfs_composite_unbind is going on, but composite_dev_cleanup not yet done) As per the traces: 23.794712: dwc3_event event=49216 ep0state=1 str= 23.794909: dwc3_ctrl_req bRequestType=161 bRequest=1 wValue=0 wIndex=2 wLength=4096 23.799740: usb_gadget_disconnect speed=5 max_speed=6 state=7 mA=0 deactivated=0 connected=0 ret=0 This indicated that android setup came first followed by composite disconnect. Since the dwc->lock was released by delegate_request, soft disconnect gets unblocked and runs parallel to composite setup. After this, there is no check in path of composite setup indicating unbind happened and bail out is necessary instead of executing any function ops. Protect composite_setup (as part of android_setup) in a spinlock to block composite_disconnect/unbind running in parallel. Moreover, in the configfs counterpart of android_setup (configfs_ composite_stetup), the composite_setup call is done with spinlock held. It is only the android_setup missing this lock. Bug: 280548269 Fixes: 7a160e2b ("ANDROID: usb: gadget: configfs: Add Uevent to notify userspace") Change-Id: Id245e9f72801541689fcb185ba0459824bfb3904 Signed-off-by:Krishna Kurapati <quic_kriskura@quicinc.com>
Loading