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

Commit b4a565e6 authored by Vijayavardhan Vennapusa's avatar Vijayavardhan Vennapusa Committed by Mayank Rana
Browse files

USB: qdss: Fix NULL pointer deference issue during QDSS transfers



There is a chance that usb_qdss_close() and disconnect race each other and
it might result in NULL pointer dereference in set_qdss_data_connection()
called from usb_qdss_close(). Fix the issue by passing qdss as argument
to set_qdss_data_connection() instead of ep.

Also remove restart call, which simulates spoof disconnect and connect,
when qdss channel is being closed, which is not required anymore as
DBM endpoints can be claimed without full USB block reset now.

Change-Id: I00642402dbe2e9595d3b3ce760ba4ed2deb2899f
Signed-off-by: default avatarVijayavardhan Vennapusa <vvreddy@codeaurora.org>
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent 79d42bd7
Loading
Loading
Loading
Loading
+3 −16
Original line number Diff line number Diff line
@@ -493,11 +493,7 @@ static void usb_qdss_disconnect_work(struct work_struct *work)
				NULL,
				NULL);

		status = set_qdss_data_connection(
				qdss->gadget,
				qdss->port.data,
				qdss->port.data->address,
				0);
		status = set_qdss_data_connection(qdss, 0);
		if (status)
			pr_err("qdss_disconnect error");
	}
@@ -543,11 +539,7 @@ static void usb_qdss_connect_work(struct work_struct *work)
	}

	pr_debug("usb_qdss_connect_work\n");
	status = set_qdss_data_connection(
			qdss->gadget,
			qdss->port.data,
			qdss->port.data->address,
			1);
	status = set_qdss_data_connection(qdss, 1);
	if (status) {
		pr_err("set_qdss_data_connection error(%d)", status);
		return;
@@ -868,14 +860,9 @@ void usb_qdss_close(struct usb_qdss_ch *ch)
	if (status)
		pr_err("%s: uninit_data error\n", __func__);

	status = set_qdss_data_connection(
				gadget,
				qdss->port.data,
				qdss->port.data->address,
				0);
	status = set_qdss_data_connection(qdss, 0);
	if (status)
		pr_err("%s:qdss_disconnect error\n", __func__);
	usb_gadget_restart(gadget);
}
EXPORT_SYMBOL(usb_qdss_close);

+1 −2
Original line number Diff line number Diff line
@@ -72,6 +72,5 @@ struct usb_qdss_opts {
};

int uninit_data(struct usb_ep *ep);
int set_qdss_data_connection(struct usb_gadget *gadget,
	struct usb_ep *data_ep, u8 data_addr, int enable);
int set_qdss_data_connection(struct f_qdss *qdss, int enable);
#endif
+14 −6
Original line number Diff line number Diff line
@@ -40,19 +40,25 @@ static int alloc_sps_req(struct usb_ep *data_ep)
}

static int init_data(struct usb_ep *ep);
int set_qdss_data_connection(struct usb_gadget *gadget,
	struct usb_ep *data_ep, u8 data_addr, int enable)
int set_qdss_data_connection(struct f_qdss *qdss, int enable)
{
	enum usb_ctrl		usb_bam_type;
	int			res = 0;
	int			idx;
	struct f_qdss *qdss = data_ep->driver_data;
	struct usb_qdss_bam_connect_info bam_info = qdss->bam_info;
	struct usb_qdss_bam_connect_info bam_info;
	struct usb_gadget *gadget;

	pr_debug("set_qdss_data_connection\n");

	if (!qdss) {
		pr_err("%s: qdss ptr is NULL\n", __func__);
		return -EINVAL;
	}

	gadget = qdss->gadget;
	usb_bam_type = usb_bam_get_bam_type(gadget->name);

	bam_info = qdss->bam_info;
	/* There is only one qdss pipe, so the pipe number can be set to 0 */
	idx = usb_bam_get_connection_idx(usb_bam_type, QDSS_P_BAM,
		PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0);
@@ -67,14 +73,16 @@ int set_qdss_data_connection(struct usb_gadget *gadget,
			kzalloc(sizeof(struct sps_mem_buffer), GFP_KERNEL);
		if (!bam_info.data_fifo) {
			pr_err("qdss_data_connection: memory alloc failed\n");
			usb_bam_free_fifos(usb_bam_type, idx);
			return -ENOMEM;
		}
		get_bam2bam_connection_info(usb_bam_type, idx,
				&bam_info.usb_bam_pipe_idx,
				NULL, bam_info.data_fifo, NULL);

		alloc_sps_req(data_ep);
		msm_data_fifo_config(data_ep, bam_info.data_fifo->phys_base,
		alloc_sps_req(qdss->port.data);
		msm_data_fifo_config(qdss->port.data,
					bam_info.data_fifo->phys_base,
					bam_info.data_fifo->size,
					bam_info.usb_bam_pipe_idx);
		init_data(qdss->port.data);