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

staging: r8712u: Fix leak of skb

There are two types of messages queued for RX. The major type, which does
I/O on the device, was being handled properly. The skbs that communicated
with the firmware were being leaked.

While rewriting the code that sets up the skb, it was possible to remove
the private variable indicating that the old skb could be reused.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Larry Finger and committed by
Greg Kroah-Hartman
78ece0b9 74a3b060

+8 -18
-1
drivers/staging/rtl8712/recv_linux.c
··· 60 60 if (!precvbuf->purb) 61 61 res = _FAIL; 62 62 precvbuf->pskb = NULL; 63 - precvbuf->reuse = false; 64 63 precvbuf->pallocated_buf = NULL; 65 64 precvbuf->pbuf = NULL; 66 65 precvbuf->pdata = NULL;
-1
drivers/staging/rtl8712/rtl8712_recv.h
··· 103 103 struct _adapter *adapter; 104 104 struct urb *purb; 105 105 _pkt *pskb; 106 - u8 reuse; 107 106 u8 irp_pending; 108 107 u32 transfer_len; 109 108 uint len;
+8 -16
drivers/staging/rtl8712/usb_ops_linux.c
··· 202 202 if (purb->status == 0) { /* SUCCESS */ 203 203 if ((purb->actual_length > (MAX_RECVBUF_SZ)) || 204 204 (purb->actual_length < RXDESC_SIZE)) { 205 - precvbuf->reuse = true; 206 205 r8712_read_port(padapter, precvpriv->ff_hwaddr, 0, 207 206 (unsigned char *)precvbuf); 208 207 } else { 208 + _pkt *pskb = precvbuf->pskb; 209 + 209 210 precvbuf->transfer_len = purb->actual_length; 210 211 pbuf = (uint *)precvbuf->pbuf; 211 212 isevt = le32_to_cpu(*(pbuf + 1)) & 0x1ff; 212 213 if ((isevt & 0x1ff) == 0x1ff) { 213 214 r8712_rxcmd_event_hdl(padapter, pbuf); 214 - precvbuf->reuse = true; 215 + skb_queue_tail(&precvpriv->rx_skb_queue, pskb); 215 216 r8712_read_port(padapter, precvpriv->ff_hwaddr, 216 217 0, (unsigned char *)precvbuf); 217 218 } else { 218 - _pkt *pskb = precvbuf->pskb; 219 - 220 219 skb_put(pskb, purb->actual_length); 221 220 skb_queue_tail(&precvpriv->rx_skb_queue, pskb); 222 221 tasklet_hi_schedule(&precvpriv->recv_tasklet); 223 - precvbuf->pskb = NULL; 224 - precvbuf->reuse = false; 225 222 r8712_read_port(padapter, precvpriv->ff_hwaddr, 226 223 0, (unsigned char *)precvbuf); 227 224 } ··· 238 241 } 239 242 /* Fall through. */ 240 243 case -EPROTO: 241 - precvbuf->reuse = true; 242 244 r8712_read_port(padapter, precvpriv->ff_hwaddr, 0, 243 245 (unsigned char *)precvbuf); 244 246 break; ··· 268 272 if (adapter->bDriverStopped || adapter->bSurpriseRemoved || 269 273 adapter->pwrctrlpriv.pnp_bstop_trx || !precvbuf) 270 274 return _FAIL; 271 - if (precvbuf->reuse || !precvbuf->pskb) { 272 - precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue); 273 - if (precvbuf->pskb != NULL) 274 - precvbuf->reuse = true; 275 - } 276 275 r8712_init_recvbuf(adapter, precvbuf); 277 - /* re-assign for linux based on skb */ 278 - if (!precvbuf->reuse || !precvbuf->pskb) { 276 + /* Try to use skb from the free queue */ 277 + precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue); 278 + 279 + if (!precvbuf->pskb) { 279 280 precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, 280 281 MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); 281 282 if (!precvbuf->pskb) ··· 286 293 precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); 287 294 precvbuf->pend = skb_end_pointer(precvbuf->pskb); 288 295 precvbuf->pbuf = precvbuf->pskb->data; 289 - } else { /* reuse skb */ 296 + } else { /* skb is reused */ 290 297 precvbuf->phead = precvbuf->pskb->head; 291 298 precvbuf->pdata = precvbuf->pskb->data; 292 299 precvbuf->ptail = skb_tail_pointer(precvbuf->pskb); 293 300 precvbuf->pend = skb_end_pointer(precvbuf->pskb); 294 301 precvbuf->pbuf = precvbuf->pskb->data; 295 - precvbuf->reuse = false; 296 302 } 297 303 purb = precvbuf->purb; 298 304 /* translate DMA FIFO addr to pipehandle */