usb: gadget: u_bam: fix race condition
On a usb cable connection/disconnection we place in a work queue the
function that is responsible to handle the connection/disconnection for
the RMNET interface.
If we connect the usb cable and disconnect it, we might get to the
condition that the connection function is running, though the usb cable
is disconnected. This may result in a NULL pointer access.
By this provided fix we check if the usb cable is disconnected before
trying to access a parameter that is set to NULL on cable disconnection.
CRs-Fixed: 468198
Change-Id: Id1a50ebc8d7f7567dab7c498a1526ee4e7ce3f7f
Signed-off-by: Shimrit Malichi <smalichi@codeaurora.org>
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 3c3fbca..1b257d0 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -714,6 +714,7 @@
ipa_notify_cb usb_notify_cb;
void *priv;
int ret;
+ unsigned long flags;
if (d->trans == USB_GADGET_XPORT_BAM2BAM) {
ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
@@ -766,9 +767,21 @@
}
}
- d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_KERNEL);
- if (!d->rx_req)
+ spin_lock_irqsave(&port->port_lock_ul, flags);
+ spin_lock(&port->port_lock_dl);
+ if (!port->port_usb) {
+ pr_debug("%s: usb cable is disconnected, exiting\n", __func__);
+ spin_unlock(&port->port_lock_dl);
+ spin_unlock_irqrestore(&port->port_lock_ul, flags);
return;
+ }
+ d->rx_req = usb_ep_alloc_request(port->port_usb->out, GFP_ATOMIC);
+ if (!d->rx_req) {
+ spin_unlock(&port->port_lock_dl);
+ spin_unlock_irqrestore(&port->port_lock_ul, flags);
+ pr_err("%s: out of memory\n", __func__);
+ return;
+ }
d->rx_req->context = port;
d->rx_req->complete = gbam_endless_rx_complete;
@@ -776,9 +789,14 @@
sps_params = (MSM_SPS_MODE | d->src_pipe_idx |
MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER;
d->rx_req->udc_priv = sps_params;
- d->tx_req = usb_ep_alloc_request(port->port_usb->in, GFP_KERNEL);
- if (!d->tx_req)
+
+ d->tx_req = usb_ep_alloc_request(port->port_usb->in, GFP_ATOMIC);
+ spin_unlock(&port->port_lock_dl);
+ spin_unlock_irqrestore(&port->port_lock_ul, flags);
+ if (!d->tx_req) {
+ pr_err("%s: out of memory\n", __func__);
return;
+ }
d->tx_req->context = port;
d->tx_req->complete = gbam_endless_tx_complete;