Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 2865d42c78a9 ("staging: r8712u: Add the new driver
to the mainline kernel"). A potential memory leak in
r8712_xmit_resource_alloc() is also addressed.

Fixes: 2865d42c78a9 ("staging: r8712u: Add the new driver to the mainline kernel")
Reported-by: 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: Larry Finger <Larry.Finger@lwfinger.net>
Reviewed-by: Nam Cao <namcaov@gmail.com>
Link: https://lore.kernel.org/r/20230714175417.18578-1-Larry.Finger@lwfinger.net
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Larry Finger and committed by
Greg Kroah-Hartman
ac836312 6eaae198

+40 -9
+34 -9
drivers/staging/rtl8712/rtl871x_xmit.c
··· 21 21 #include "osdep_intf.h" 22 22 #include "usb_ops.h" 23 23 24 + #include <linux/usb.h> 24 25 #include <linux/ieee80211.h> 25 26 26 27 static const u8 P802_1H_OUI[P80211_OUI_LEN] = {0x00, 0x00, 0xf8}; ··· 56 55 sint i; 57 56 struct xmit_buf *pxmitbuf; 58 57 struct xmit_frame *pxframe; 58 + int j; 59 59 60 60 memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv)); 61 61 spin_lock_init(&pxmitpriv->lock); ··· 119 117 _init_queue(&pxmitpriv->pending_xmitbuf_queue); 120 118 pxmitpriv->pallocated_xmitbuf = 121 119 kmalloc(NR_XMITBUFF * sizeof(struct xmit_buf) + 4, GFP_ATOMIC); 122 - if (!pxmitpriv->pallocated_xmitbuf) { 123 - kfree(pxmitpriv->pallocated_frame_buf); 124 - pxmitpriv->pallocated_frame_buf = NULL; 125 - return -ENOMEM; 126 - } 120 + if (!pxmitpriv->pallocated_xmitbuf) 121 + goto clean_up_frame_buf; 127 122 pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 - 128 123 ((addr_t)(pxmitpriv->pallocated_xmitbuf) & 3); 129 124 pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmitbuf; ··· 128 129 INIT_LIST_HEAD(&pxmitbuf->list); 129 130 pxmitbuf->pallocated_buf = 130 131 kmalloc(MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ, GFP_ATOMIC); 131 - if (!pxmitbuf->pallocated_buf) 132 - return -ENOMEM; 132 + if (!pxmitbuf->pallocated_buf) { 133 + j = 0; 134 + goto clean_up_alloc_buf; 135 + } 133 136 pxmitbuf->pbuf = pxmitbuf->pallocated_buf + XMITBUF_ALIGN_SZ - 134 137 ((addr_t) (pxmitbuf->pallocated_buf) & 135 138 (XMITBUF_ALIGN_SZ - 1)); 136 - if (r8712_xmit_resource_alloc(padapter, pxmitbuf)) 137 - return -ENOMEM; 139 + if (r8712_xmit_resource_alloc(padapter, pxmitbuf)) { 140 + j = 1; 141 + goto clean_up_alloc_buf; 142 + } 138 143 list_add_tail(&pxmitbuf->list, 139 144 &(pxmitpriv->free_xmitbuf_queue.queue)); 140 145 pxmitbuf++; ··· 149 146 init_hwxmits(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry); 150 147 tasklet_setup(&pxmitpriv->xmit_tasklet, r8712_xmit_bh); 151 148 return 0; 149 + 150 + clean_up_alloc_buf: 151 + if (j) { 152 + /* failure happened in r8712_xmit_resource_alloc() 153 + * delete extra pxmitbuf->pallocated_buf 154 + */ 155 + kfree(pxmitbuf->pallocated_buf); 156 + } 157 + for (j = 0; j < i; j++) { 158 + int k; 159 + 160 + pxmitbuf--; /* reset pointer */ 161 + kfree(pxmitbuf->pallocated_buf); 162 + for (k = 0; k < 8; k++) /* delete xmit urb's */ 163 + usb_free_urb(pxmitbuf->pxmit_urb[k]); 164 + } 165 + kfree(pxmitpriv->pallocated_xmitbuf); 166 + pxmitpriv->pallocated_xmitbuf = NULL; 167 + clean_up_frame_buf: 168 + kfree(pxmitpriv->pallocated_frame_buf); 169 + pxmitpriv->pallocated_frame_buf = NULL; 170 + return -ENOMEM; 152 171 } 153 172 154 173 void _free_xmit_priv(struct xmit_priv *pxmitpriv)
+6
drivers/staging/rtl8712/xmit_linux.c
··· 112 112 for (i = 0; i < 8; i++) { 113 113 pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL); 114 114 if (!pxmitbuf->pxmit_urb[i]) { 115 + int k; 116 + 117 + for (k = i - 1; k >= 0; k--) { 118 + /* handle allocation errors part way through loop */ 119 + usb_free_urb(pxmitbuf->pxmit_urb[k]); 120 + } 115 121 netdev_err(padapter->pnetdev, "pxmitbuf->pxmit_urb[i] == NULL\n"); 116 122 return -ENOMEM; 117 123 }