usb: smd: Fix crash during reset when RmNet is connected
When a QMI/RMNET control connection is established, a diag
reset causes a crash due to a NULL pointer dereference. The
SMD channel pointer is set to NULL upon USB cable disconnect,
but a queued work function might still try to access that pointer.
Fix the crash by checking for NULL pointers in both smd_* and in
USB gadget transport functions that could pass a closed handle.
CRs-fixed: 336850
Change-Id: I87cb109f3e7007efe15b5acc81180151dd2ef023
Signed-off-by: Jack Pham <jackp@codeaurora.org>
diff --git a/drivers/usb/gadget/u_smd.c b/drivers/usb/gadget/u_smd.c
index e74b2e1..a5ceaff 100644
--- a/drivers/usb/gadget/u_smd.c
+++ b/drivers/usb/gadget/u_smd.c
@@ -209,6 +209,7 @@
static void gsmd_rx_push(struct work_struct *w)
{
struct gsmd_port *port = container_of(w, struct gsmd_port, push);
+ struct smd_port_info *pi = port->pi;
struct list_head *q;
pr_debug("%s: port:%p port#%d", __func__, port, port->port_num);
@@ -216,10 +217,9 @@
spin_lock_irq(&port->port_lock);
q = &port->read_queue;
- while (!list_empty(q)) {
+ while (pi->ch && !list_empty(q)) {
struct usb_request *req;
int avail;
- struct smd_port_info *pi = port->pi;
req = list_first_entry(q, struct usb_request, list);
@@ -296,21 +296,24 @@
{
struct gsmd_port *port = container_of(w, struct gsmd_port, pull);
struct list_head *pool = &port->write_pool;
+ struct smd_port_info *pi = port->pi;
+ struct usb_ep *in;
pr_debug("%s: port:%p port#%d pool:%p\n", __func__,
port, port->port_num, pool);
+ spin_lock_irq(&port->port_lock);
+
if (!port->port_usb) {
pr_debug("%s: usb is disconnected\n", __func__);
+ spin_unlock_irq(&port->port_lock);
gsmd_read_pending(port);
return;
}
- spin_lock_irq(&port->port_lock);
- while (!list_empty(pool)) {
+ in = port->port_usb->in;
+ while (pi->ch && !list_empty(pool)) {
struct usb_request *req;
- struct usb_ep *in = port->port_usb->in;
- struct smd_port_info *pi = port->pi;
int avail;
int ret;