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

Commit fc8320a3 authored by Manu Gautam's avatar Manu Gautam
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.

CRs-fixed: 595367
Change-Id: I181da831120b38840ae4b8b74c1dacce129d1ba6
Signed-off-by: default avatarManu Gautam <mgautam@codeaurora.org>
parent 077dfa98
Loading
Loading
Loading
Loading
+18 −3
Original line number Diff line number Diff line
@@ -598,7 +598,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;
@@ -664,6 +664,14 @@ static void tx_complete(struct usb_ep *ep, struct usb_request *req)
		}
	} else {
		skb = req->context;
		/* 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);
	}
@@ -691,12 +699,15 @@ static int alloc_tx_buffer(struct eth_dev *dev)

	list_for_each(act, &dev->tx_reqs) {
		req = container_of(act, struct usb_request, list);
		if (!req->buf)
		if (!req->buf) {
			req->buf = kzalloc(dev->tx_req_bufsize,
						GFP_ATOMIC);
			if (!req->buf)
				goto free_buf;
		}
		/* req->context is not used for multi_pkt_xfers */
		req->context = NULL;
	}
	return 0;

free_buf:
@@ -739,11 +750,15 @@ 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 only for ETH packets */
	if (!test_bit(RMNET_MODE_LLP_IP, &dev->flags) &&