diff options
| author | Vijayavardhan Vennapusa <vvreddy@codeaurora.org> | 2017-02-14 11:21:53 +0530 |
|---|---|---|
| committer | Vijayavardhan Vennapusa <vvreddy@codeaurora.org> | 2017-02-14 16:54:01 +0530 |
| commit | 273dcf1abb80b9d100ba0f02aacc8bd22f9a67d3 (patch) | |
| tree | f075f851a8706f3303a900fde47cb2adc76a5eb4 | |
| parent | 3a7e752617514960c5cecdf84e12b13dc63c04c7 (diff) | |
USB: u_data_ipa: Fix NULL pointer dereference before starting RX/TX
If disconnect happens before connect_work done, there is a chance that
port_usb might be NULL before calling ipa_data_start_rx_tx(). This could
cause crash if it happens. Fix it by taking to local variable under
spin lock protection and check later before calling ipa_data_start_rx_tx()
for queuing RX/TX requests to USB HW.
Change-Id: I82d74e34bb4d29eac225d31dac67bf5d5bc39a79
Signed-off-by: Vijayavardhan Vennapusa <vvreddy@codeaurora.org>
| -rw-r--r-- | drivers/usb/gadget/function/u_data_ipa.c | 31 |
1 files changed, 23 insertions, 8 deletions
diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c index 83a98f1196f8..4975ba474f97 100644 --- a/drivers/usb/gadget/function/u_data_ipa.c +++ b/drivers/usb/gadget/function/u_data_ipa.c @@ -95,6 +95,7 @@ static void ipa_data_start_endless_xfer(struct ipa_data_ch_info *port, bool in) { unsigned long flags; int status; + struct usb_ep *ep; spin_lock_irqsave(&port->port_lock, flags); if (!port->port_usb || (in && !port->tx_req) @@ -103,18 +104,22 @@ static void ipa_data_start_endless_xfer(struct ipa_data_ch_info *port, bool in) pr_err("%s(): port_usb/req is NULL.\n", __func__); return; } + + if (in) + ep = port->port_usb->in; + else + ep = port->port_usb->out; + spin_unlock_irqrestore(&port->port_lock, flags); if (in) { pr_debug("%s: enqueue endless TX_REQ(IN)\n", __func__); - status = usb_ep_queue(port->port_usb->in, - port->tx_req, GFP_ATOMIC); + status = usb_ep_queue(ep, port->tx_req, GFP_ATOMIC); if (status) pr_err("error enqueuing endless TX_REQ, %d\n", status); } else { pr_debug("%s: enqueue endless RX_REQ(OUT)\n", __func__); - status = usb_ep_queue(port->port_usb->out, - port->rx_req, GFP_ATOMIC); + status = usb_ep_queue(ep, port->rx_req, GFP_ATOMIC); if (status) pr_err("error enqueuing endless RX_REQ, %d\n", status); } @@ -132,6 +137,7 @@ static void ipa_data_stop_endless_xfer(struct ipa_data_ch_info *port, bool in) { unsigned long flags; int status; + struct usb_ep *ep; spin_lock_irqsave(&port->port_lock, flags); if (!port->port_usb || (in && !port->tx_req) @@ -140,16 +146,22 @@ static void ipa_data_stop_endless_xfer(struct ipa_data_ch_info *port, bool in) pr_err("%s(): port_usb/req is NULL.\n", __func__); return; } + + if (in) + ep = port->port_usb->in; + else + ep = port->port_usb->out; + spin_unlock_irqrestore(&port->port_lock, flags); if (in) { pr_debug("%s: dequeue endless TX_REQ(IN)\n", __func__); - status = usb_ep_dequeue(port->port_usb->in, port->tx_req); + status = usb_ep_dequeue(ep, port->tx_req); if (status) pr_err("error dequeueing endless TX_REQ, %d\n", status); } else { pr_debug("%s: dequeue endless RX_REQ(OUT)\n", __func__); - status = usb_ep_dequeue(port->port_usb->out, port->rx_req); + status = usb_ep_dequeue(ep, port->rx_req); if (status) pr_err("error dequeueing endless RX_REQ, %d\n", status); } @@ -164,6 +176,7 @@ void ipa_data_start_rx_tx(enum ipa_func_type func) { struct ipa_data_ch_info *port; unsigned long flags; + struct usb_ep *epin, *epout; pr_debug("%s: Triggered: starting tx, rx", __func__); /* queue in & out requests */ @@ -194,15 +207,17 @@ void ipa_data_start_rx_tx(enum ipa_func_type func) return; } + epout = port->port_usb->out; + epin = port->port_usb->in; spin_unlock_irqrestore(&port->port_lock, flags); /* queue in & out requests */ pr_debug("%s: Starting rx", __func__); - if (port->port_usb->out) + if (epout) ipa_data_start_endless_xfer(port, false); pr_debug("%s: Starting tx", __func__); - if (port->port_usb->in) + if (epin) ipa_data_start_endless_xfer(port, true); } /** |
