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

Commit f8afc31a authored by Manu Gautam's avatar Manu Gautam Committed by Gerrit - the friendly Code Review server
Browse files

USB: gadget: ether: Fix memory corruption issues with multi_pkt_xfers



If gadget xmits packets before host sends RNDIS_MSG_INIT to
update maximum packets supported per transfer, then there is a
possibility of using freed skb memory later from xmit function.
Fix such races which may arise between tx_complete and start_xmit
routines depending on when multi_pkt_transfers are enabled. Other
option is to defer starting TX transfers until RNDIS_MSG_INIT is
received, but then it makes it difficult to handle scenarios
where host doesn't support this message or just doesn't send it.

Change-Id: I181da831120b38840ae4b8b74c1dacce129d1ba6
Signed-off-by: default avatarManu Gautam <mgautam@codeaurora.org>
Signed-off-by: default avatarAjay Agarwal <ajaya@codeaurora.org>
parent 6481d889
Loading
Loading
Loading
Loading
+18 −2
Original line number Diff line number Diff line
@@ -543,7 +543,7 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req)
	spin_lock(&dev->req_lock);
	list_add_tail(&req->list, &dev->tx_reqs);

	if (dev->port_usb->multi_pkt_xfer) {
	if (dev->port_usb->multi_pkt_xfer && !req->context) {
		dev->no_tx_req_used--;
		req->length = 0;
		in = dev->port_usb->in_ep;
@@ -608,6 +608,14 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req)
			spin_unlock(&dev->req_lock);
		}
	} else {
		/* Is aggregation already enabled and buffers allocated ? */
		if (dev->port_usb->multi_pkt_xfer && dev->tx_req_bufsize) {
			req->buf = kzalloc(dev->tx_req_bufsize, GFP_ATOMIC);
			req->context = NULL;
		} else {
			req->buf = NULL;
		}

		spin_unlock(&dev->req_lock);
		dev_kfree_skb_any(skb);
	}
@@ -641,6 +649,9 @@ static int alloc_tx_buffer(struct eth_dev *dev)

		if (!req->buf)
			goto free_buf;

		/* req->context is not used for multi_pkt_xfers */
		req->context = NULL;
	}
	return 0;

@@ -684,11 +695,16 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
	}

	/* Allocate memory for tx_reqs to support multi packet transfer */
	spin_lock_irqsave(&dev->req_lock, flags);
	if (multi_pkt_xfer && !dev->tx_req_bufsize) {
		retval = alloc_tx_buffer(dev);
		if (retval < 0)
		if (retval < 0) {
			spin_unlock_irqrestore(&dev->req_lock, flags);
			return -ENOMEM;
		}
	}

	spin_unlock_irqrestore(&dev->req_lock, flags);

	/* apply outgoing CDC or RNDIS filters */
	if (skb && !is_promisc(cdc_filter)) {