u_ether: Handle memory allocation failure case on tx path
With multipacket feature enabled, if the memory allocation for
tx request buffer fails, accessing the req->buf leads to null
pointer dereference.
Hence, handle memory alloction failure case and return -ENOMEM.
Change-Id: Ic5faac8ea7eb056755b03007c48ff085f10afa20
Signed-off-by: Rajkumar Raghupathy <raghup@codeaurora.org>
Signed-off-by: Ajay Agarwal <ajaya@codeaurora.org>
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 41050af..4dbeba1 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -613,7 +613,7 @@
return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
}
-static void alloc_tx_buffer(struct eth_dev *dev)
+static int alloc_tx_buffer(struct eth_dev *dev)
{
struct list_head *act;
struct usb_request *req;
@@ -630,7 +630,21 @@
if (!req->buf)
req->buf = kmalloc(dev->tx_req_bufsize,
GFP_ATOMIC);
+
+ if (!req->buf)
+ goto free_buf;
}
+ return 0;
+
+free_buf:
+ /* tx_req_bufsize = 0 retries mem alloc on next eth_start_xmit */
+ dev->tx_req_bufsize = 0;
+ list_for_each(act, &dev->tx_reqs) {
+ req = container_of(act, struct usb_request, list);
+ kfree(req->buf);
+ req->buf = NULL;
+ }
+ return -ENOMEM;
}
static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
@@ -662,8 +676,11 @@
}
/* Allocate memory for tx_reqs to support multi packet transfer */
- if (multi_pkt_xfer && !dev->tx_req_bufsize)
- alloc_tx_buffer(dev);
+ if (multi_pkt_xfer && !dev->tx_req_bufsize) {
+ retval = alloc_tx_buffer(dev);
+ if (retval < 0)
+ return -ENOMEM;
+ }
/* apply outgoing CDC or RNDIS filters */
if (skb && !is_promisc(cdc_filter)) {
@@ -1534,8 +1551,10 @@
list_del(&req->list);
spin_unlock(&dev->req_lock);
- if (link->multi_pkt_xfer)
+ if (link->multi_pkt_xfer) {
kfree(req->buf);
+ req->buf = NULL;
+ }
usb_ep_free_request(link->in_ep, req);
spin_lock(&dev->req_lock);
}