Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f3a965ed authored by Manu Gautam's avatar Manu Gautam
Browse files

USB: gadget: u_bam_data: Check USB state under spinlock



While starting/stopping endless transfers, USB may get
disconnected. This is checked using port_data just before
calling usb_ep_queue. But, this is possibility of disconnect
happening after this check resulting in NULL pointer
dereference when accessing port_usb->in/out EPs. Fix this
by checking for cable connection under spinlock and using
a copy of EP context for calling usb_ep_queue.

Change-Id: I196650223f1350a5c5cc2cd173a67dc3c64c2dc6
CRs-fixed: 756048
Signed-off-by: default avatarManu Gautam <mgautam@codeaurora.org>
parent fffe6d0f
Loading
Loading
Loading
Loading
+29 −8
Original line number Diff line number Diff line
@@ -595,14 +595,20 @@ static void bam_data_endless_tx_complete(struct usb_ep *ep,
static void bam_data_start_endless_rx(struct bam_data_port *port)
{
	struct bam_data_ch_info *d = &port->data_ch;
	struct usb_ep *ep;
	unsigned long flags;
	int status;

	spin_lock_irqsave(&port->port_lock, flags);
	if (!port->port_usb) {
		spin_unlock_irqrestore(&port->port_lock, flags);
		return;
	}
	ep = port->port_usb->out;
	spin_unlock_irqrestore(&port->port_lock, flags);

	pr_debug("%s: enqueue\n", __func__);
	status = usb_ep_queue(port->port_usb->out, d->rx_req, GFP_ATOMIC);
	status = usb_ep_queue(ep, d->rx_req, GFP_ATOMIC);
	if (status)
		pr_err("error enqueuing transfer, %d\n", status);
}
@@ -610,13 +616,20 @@ static void bam_data_start_endless_rx(struct bam_data_port *port)
static void bam_data_start_endless_tx(struct bam_data_port *port)
{
	struct bam_data_ch_info *d = &port->data_ch;
	struct usb_ep *ep;
	unsigned long flags;
	int status;

	if (!port->port_usb)
	spin_lock_irqsave(&port->port_lock, flags);
	if (!port->port_usb) {
		spin_unlock_irqrestore(&port->port_lock, flags);
		return;
	}
	ep = port->port_usb->in;
	spin_unlock_irqrestore(&port->port_lock, flags);

	pr_debug("%s: enqueue\n", __func__);
	status = usb_ep_queue(port->port_usb->in, d->tx_req, GFP_ATOMIC);
	status = usb_ep_queue(ep, d->tx_req, GFP_ATOMIC);
	if (status)
		pr_err("error enqueuing transfer, %d\n", status);
}
@@ -624,11 +637,12 @@ static void bam_data_start_endless_tx(struct bam_data_port *port)
static void bam_data_stop_endless_rx(struct bam_data_port *port)
{
	struct bam_data_ch_info *d = &port->data_ch;
	unsigned long flags;
	int status;

	spin_lock(&port->port_lock);
	spin_lock_irqsave(&port->port_lock, flags);
	if (!port->port_usb) {
		spin_unlock(&port->port_lock);
		spin_unlock_irqrestore(&port->port_lock, flags);
		return;
	}

@@ -637,18 +651,25 @@ static void bam_data_stop_endless_rx(struct bam_data_port *port)
	if (status)
		pr_err("%s: error dequeuing transfer, %d\n", __func__, status);

	spin_unlock(&port->port_lock);
	spin_unlock_irqrestore(&port->port_lock, flags);
}
static void bam_data_stop_endless_tx(struct bam_data_port *port)
{
	struct bam_data_ch_info *d = &port->data_ch;
	struct usb_ep *ep;
	unsigned long flags;
	int status;

	if (!port->port_usb)
	spin_lock_irqsave(&port->port_lock, flags);
	if (!port->port_usb) {
		spin_unlock_irqrestore(&port->port_lock, flags);
		return;
	}
	ep = port->port_usb->in;
	spin_unlock_irqrestore(&port->port_lock, flags);

	pr_debug("%s: dequeue\n", __func__);
	status = usb_ep_dequeue(port->port_usb->in, d->tx_req);
	status = usb_ep_dequeue(ep, d->tx_req);
	if (status)
		pr_err("%s: error dequeuing transfer, %d\n", __func__, status);
}