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

Commit 46cbba42 authored by Manu Gautam's avatar Manu Gautam Committed by Sivasri Kumar Vanka
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 the 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 avatarSivasri Kumar Vanka <sivasri@codeaurora.org>
parent aaa66667
Loading
Loading
Loading
Loading
+18 −2
Original line number Diff line number Diff line
@@ -582,7 +582,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;
@@ -649,6 +649,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);
	}
@@ -682,6 +690,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;

@@ -725,11 +736,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)) {