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

Commit 457ac5b0 authored by Mayank Rana's avatar Mayank Rana
Browse files

USB: gadget: Fix race condition to over come memory corruption



With dynamic composition change, it has been observed that port
structure is being accessed after it is being freed. Hence it
creates memory corruption and device is crashing with the same.
This change avoid port access after it is being freed to ovecome
this issue.

CRs-Fixed: 636780
Change-Id: Ibc2792791cecbcea63edeba864df7b7da73b5f40
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent 2a9b24f2
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1709,7 +1709,6 @@ static void mbim_unbind(struct usb_configuration *c, struct usb_function *f)
	struct f_mbim	*mbim = func_to_mbim(f);

	pr_debug("unbinding mbim\n");
	bam_data_destroy(mbim->port_num);

	if (gadget_is_superspeed(c->cdev->gadget))
		usb_free_descriptors(f->ss_descriptors);
@@ -1722,6 +1721,7 @@ static void mbim_unbind(struct usb_configuration *c, struct usb_function *f)
	usb_ep_free_request(mbim->not_port.notify, mbim->not_port.notify_req);

	mbim_ext_config_desc.function.subCompatibleID[0] = 0;
	bam_work_destroy();
}

/**
+1 −2
Original line number Diff line number Diff line
@@ -1016,8 +1016,6 @@ ecm_qc_unbind(struct usb_configuration *c, struct usb_function *f)

	DBG(c->cdev, "ecm unbind\n");

	bam_data_destroy(0);

	if (gadget_is_superspeed(c->cdev->gadget))
		usb_free_descriptors(f->ss_descriptors);
	if (gadget_is_dualspeed(c->cdev->gadget))
@@ -1033,6 +1031,7 @@ ecm_qc_unbind(struct usb_configuration *c, struct usb_function *f)
		ecm_ipa_cleanup(ipa_params.private);

	kfree(ecm);
	bam_work_destroy();
}

/**
+1 −1
Original line number Diff line number Diff line
@@ -1028,7 +1028,6 @@ rndis_qc_unbind(struct usb_configuration *c, struct usb_function *f)
	struct f_rndis_qc		*rndis = func_to_rndis_qc(f);

	pr_debug("rndis_qc_unbind: free\n");
	bam_data_destroy(0);
	rndis_deregister(rndis->config);
	rndis_exit();

@@ -1045,6 +1044,7 @@ rndis_qc_unbind(struct usb_configuration *c, struct usb_function *f)
	}

	kfree(rndis);
	bam_work_destroy();
}

bool is_rndis_ipa_supported(void)
+22 −5
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@ static struct rndis_data_ch_info rndis_data;

static void bam2bam_data_suspend_work(struct work_struct *w);
static void bam2bam_data_resume_work(struct work_struct *w);
static void bam2bam_data_port_free(int portno);

/*----- sys2bam towards the IPA (UL workaround) --------------- */

@@ -618,10 +619,16 @@ static void bam2bam_data_disconnect_work(struct work_struct *w)
		}

		ret = usb_bam_disconnect_ipa(&d->ipa_params);
		if (ret)
		if (!ret) {
			pr_debug("%s(): freeing bam2bam_data_port\n", __func__);
			bam2bam_data_port_free(0);
		} else {
			pr_err("usb_bam_disconnect_ipa failed: err:%d\n", ret);
		}

		if (d->func_type == USB_FUNC_MBIM)
			teth_bridge_disconnect(d->ipa_params.src_client);

	}

	port->is_connected = false;
@@ -968,14 +975,17 @@ static void bam2bam_data_connect_work(struct work_struct *w)

static void bam2bam_data_port_free(int portno)
{
	if (bam2bam_data_ports[portno] == NULL) {
	struct bam_data_port *port = bam2bam_data_ports[portno];

	if (port == NULL) {
		pr_debug("port %d already free\n", portno);
		return;
	}

	if (--bam2bam_data_ports[portno]->ref_count == 0) {
		kfree(bam2bam_data_ports[portno]);
		bam2bam_data_ports[portno] = NULL;
	if (--port->ref_count == 0) {
		kfree(port);
		port = NULL;
		n_bam2bam_data_ports--;
		pr_debug("freed port %d\n", portno);
	}
}
@@ -1238,6 +1248,13 @@ int bam_data_destroy(unsigned int no_bam2bam_port)
	return 0;
}

void bam_work_destroy(void)
{
	if (bam_data_wq)
		destroy_workqueue(bam_data_wq);
	bam_data_wq = NULL;
}

int bam_data_setup(unsigned int no_bam2bam_port)
{
	int	i;
+1 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ int bam_data_connect(struct data_port *gr, u8 port_num,

int bam_data_setup(unsigned int no_bam2bam_port);

int bam_data_destroy(unsigned int no_bam2bam_port);
void bam_work_destroy(void);

void bam_data_suspend(u8 port_num);