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

Commit 955d9939 authored by Elson Roy Serrao's avatar Elson Roy Serrao
Browse files

usb: f_qdss: dequeue pending requests upon qdss close



When qdss_close is called the pending requests sent to the
controller are not stopped and as a result the completion
call back can occur at any time. If the qdss bridge driver
frees the requests before the completion callback may result
in use after free. Call dequeue on the pending requests in
qdss close so that the requests are terminated instantly.

Change-Id: I2752a598e8b104a6803064343743f591adc924e4
Signed-off-by: default avatarElson Roy Serrao <eserrao@codeaurora.org>
parent d66d368d
Loading
Loading
Loading
Loading
+26 −4
Original line number Diff line number Diff line
@@ -238,6 +238,8 @@ static void qdss_write_complete(struct usb_ep *ep,
	}

	spin_lock_irqsave(&qdss->lock, flags);
	if (!qdss->debug_inface_enabled)
		list_del(&req->list);
	list_add_tail(&req->list, list_pool);
	if (req->length != 0) {
		d_req->actual = req->actual;
@@ -792,6 +794,7 @@ static struct f_qdss *alloc_usb_qdss(char *channel_name)
	INIT_LIST_HEAD(&qdss->ctrl_read_pool);
	INIT_LIST_HEAD(&qdss->ctrl_write_pool);
	INIT_LIST_HEAD(&qdss->data_write_pool);
	INIT_LIST_HEAD(&qdss->queued_data_pool);
	INIT_WORK(&qdss->connect_w, usb_qdss_connect_work);
	INIT_WORK(&qdss->disconnect_w, usb_qdss_disconnect_work);

@@ -893,14 +896,14 @@ int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req)
	unsigned long flags;
	struct usb_request *req = NULL;

	pr_debug("usb_qdss_ctrl_write\n");
	pr_debug("usb_qdss_data_write\n");

	if (!qdss)
		return -ENODEV;

	spin_lock_irqsave(&qdss->lock, flags);

	if (qdss->usb_connected == 0) {
	if (qdss->qdss_close || qdss->usb_connected == 0) {
		spin_unlock_irqrestore(&qdss->lock, flags);
		return -EIO;
	}
@@ -913,7 +916,7 @@ int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req)

	req = list_first_entry(&qdss->data_write_pool, struct usb_request,
		list);
	list_del(&req->list);
	list_move_tail(&req->list, &qdss->queued_data_pool);
	spin_unlock_irqrestore(&qdss->lock, flags);

	req->buf = d_req->buf;
@@ -924,7 +927,8 @@ int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req)
	req->num_mapped_sgs = d_req->num_mapped_sgs;
	if (usb_ep_queue(qdss->port.data, req, GFP_ATOMIC)) {
		spin_lock_irqsave(&qdss->lock, flags);
		list_add_tail(&req->list, &qdss->data_write_pool);
		/* Remove from queued pool and add back to data pool */
		list_move_tail(&req->list, &qdss->data_write_pool);
		spin_unlock_irqrestore(&qdss->lock, flags);
		pr_err("qdss usb_ep_queue failed\n");
		return -EIO;
@@ -971,6 +975,7 @@ struct usb_qdss_ch *usb_qdss_open(const char *name, void *priv,
	ch->priv = priv;
	ch->notify = notify;
	ch->app_conn = 1;
	qdss->qdss_close = false;
	spin_unlock_irqrestore(&qdss_lock, flags);

	/* the case USB cabel was connected before qdss called qdss_open */
@@ -987,10 +992,27 @@ void usb_qdss_close(struct usb_qdss_ch *ch)
	struct usb_gadget *gadget;
	unsigned long flags;
	int status;
	struct usb_request *req;

	pr_debug("%s\n", __func__);

	spin_lock_irqsave(&qdss_lock, flags);
	if (!qdss)
		goto close;
	qdss->qdss_close = true;
	while (!list_empty(&qdss->queued_data_pool)) {
		req = list_first_entry(&qdss->queued_data_pool,
				struct usb_request, list);
		spin_unlock_irqrestore(&qdss_lock, flags);
		if (usb_ep_dequeue(qdss->port.data, req)) {
			spin_lock_irqsave(&qdss_lock, flags);
			list_move_tail(&req->list, &qdss->data_write_pool);
			spin_unlock_irqrestore(&qdss_lock, flags);
		}
		spin_lock_irqsave(&qdss_lock, flags);
	}
	usb_qdss_free_req(ch);
close:
	ch->priv_usb = NULL;
	if (!qdss || !qdss->usb_connected ||
			!strcmp(qdss->ch.name, USB_QDSS_CH_MDM)) {
+3 −1
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
 */

#ifndef _F_QDSS_H
@@ -54,6 +54,7 @@ struct f_qdss {

	/* for mdm channel SW path */
	struct list_head data_write_pool;
	struct list_head queued_data_pool;

	struct work_struct connect_w;
	struct work_struct disconnect_w;
@@ -62,6 +63,7 @@ struct f_qdss {
	unsigned int ctrl_in_enabled:1;
	unsigned int ctrl_out_enabled:1;
	struct workqueue_struct *wq;
	bool qdss_close;
};

struct usb_qdss_opts {