Commit ac836312 authored by Larry Finger's avatar Larry Finger Committed by Greg Kroah-Hartman
Browse files

staging: r8712: Fix memory leak in _r8712_init_xmit_priv()



In the above mentioned routine, memory is allocated in several places.
If the first succeeds and a later one fails, the routine will leak memory.
This patch fixes commit 2865d42c ("staging: r8712u: Add the new driver
to the mainline kernel"). A potential memory leak in
r8712_xmit_resource_alloc() is also addressed.

Fixes: 2865d42c ("staging: r8712u: Add the new driver to the mainline kernel")
Reported-by: default avatar <syzbot+cf71097ffb6755df8251@syzkaller.appspotmail.com>
Closes: https://syzkaller.appspot.com/x/log.txt?x=11ac3fa0a80000


Cc: stable@vger.kernel.org
Cc: Nam Cao <namcaov@gmail.com>
Signed-off-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Reviewed-by: default avatarNam Cao <namcaov@gmail.com>
Link: https://lore.kernel.org/r/20230714175417.18578-1-Larry.Finger@lwfinger.net


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 6eaae198
Loading
Loading
Loading
Loading
+34 −9
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "osdep_intf.h"
#include "usb_ops.h"

#include <linux/usb.h>
#include <linux/ieee80211.h>

static const u8 P802_1H_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0xf8};
@@ -55,6 +56,7 @@ int _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
	sint i;
	struct xmit_buf *pxmitbuf;
	struct xmit_frame *pxframe;
	int j;

	memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv));
	spin_lock_init(&pxmitpriv->lock);
@@ -117,11 +119,8 @@ int _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
	_init_queue(&pxmitpriv->pending_xmitbuf_queue);
	pxmitpriv->pallocated_xmitbuf =
		kmalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4, GFP_ATOMIC);
	if (!pxmitpriv->pallocated_xmitbuf) {
		kfree(pxmitpriv->pallocated_frame_buf);
		pxmitpriv->pallocated_frame_buf = NULL;
		return -ENOMEM;
	}
	if (!pxmitpriv->pallocated_xmitbuf)
		goto clean_up_frame_buf;
	pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 -
			      ((addr_t)(pxmitpriv->pallocated_xmitbuf) & 3);
	pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf;
@@ -129,13 +128,17 @@ int _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
		INIT_LIST_HEAD(&pxmitbuf->list);
		pxmitbuf->pallocated_buf =
			kmalloc(MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ, GFP_ATOMIC);
		if (!pxmitbuf->pallocated_buf)
			return -ENOMEM;
		if (!pxmitbuf->pallocated_buf) {
			j = 0;
			goto clean_up_alloc_buf;
		}
		pxmitbuf->pbuf = pxmitbuf->pallocated_buf + XMITBUF_ALIGN_SZ -
				 ((addr_t) (pxmitbuf->pallocated_buf) &
				 (XMITBUF_ALIGN_SZ - 1));
		if (r8712_xmit_resource_alloc(padapter, pxmitbuf))
			return -ENOMEM;
		if (r8712_xmit_resource_alloc(padapter, pxmitbuf)) {
			j = 1;
			goto clean_up_alloc_buf;
		}
		list_add_tail(&pxmitbuf->list,
				 &(pxmitpriv->free_xmitbuf_queue.queue));
		pxmitbuf++;
@@ -146,6 +149,28 @@ int _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
	init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
	tasklet_setup(&pxmitpriv->xmit_tasklet, r8712_xmit_bh);
	return 0;

clean_up_alloc_buf:
	if (j) {
		/* failure happened in r8712_xmit_resource_alloc()
		 * delete extra pxmitbuf->pallocated_buf
		 */
		kfree(pxmitbuf->pallocated_buf);
	}
	for (j = 0; j < i; j++) {
		int k;

		pxmitbuf--;			/* reset pointer */
		kfree(pxmitbuf->pallocated_buf);
		for (k = 0; k < 8; k++)		/* delete xmit urb's */
			usb_free_urb(pxmitbuf->pxmit_urb[k]);
	}
	kfree(pxmitpriv->pallocated_xmitbuf);
	pxmitpriv->pallocated_xmitbuf = NULL;
clean_up_frame_buf:
	kfree(pxmitpriv->pallocated_frame_buf);
	pxmitpriv->pallocated_frame_buf = NULL;
	return -ENOMEM;
}

void _free_xmit_priv(struct xmit_priv *pxmitpriv)
+6 −0
Original line number Diff line number Diff line
@@ -112,6 +112,12 @@ int r8712_xmit_resource_alloc(struct _adapter *padapter,
	for (i = 0; i < 8; i++) {
		pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
		if (!pxmitbuf->pxmit_urb[i]) {
			int k;

			for (k = i - 1; k >= 0; k--) {
				/* handle allocation errors part way through loop */
				usb_free_urb(pxmitbuf->pxmit_urb[k]);
			}
			netdev_err(padapter->pnetdev, "pxmitbuf->pxmit_urb[i] == NULL\n");
			return -ENOMEM;
		}