can: fix same memory leaks in can drivers
Subsystems (3)
cover can: fix same memory leaks in can drivers
Hi, Marc and can drivers maintainers/reviewers!
A long time ago syzbot reported memory leak in mcba_usb can driver[1]. It was using strange pattern for allocating coherent buffers, which was leading to memory leaks. Yesterday I got a report, that mcba_usb stopped working since my commit. I came up with quick fix and all started working well.
There are at least 3 more drivers with this pattern, I decided to fix leaks in them too, since code is actually the same (I guess, driver authors just copy pasted code parts). Each of following patches is combination of 91c02557174b ("can: mcba_usb: fix memory leak in mcba_usb") and my yesterday fix [2].
Dear maintainers/reviewers, if You have one of these hardware pieces, please, test these patches and report any errors you will find.
[1] https://syzkaller.appspot.com/bug?id=c94c1c23e829d5ac97995d51219f0c5a0cd1fa54
[2] https://lore.kernel.org/netdev/[email protected]/
With regards,
Pavel Skripkin
Pavel Skripkin (3):
can: usb_8dev: fix memory leak
can: ems_usb: fix memory leak
can: esd_usb2: fix memory leak
drivers/net/can/usb/ems_usb.c | 14 +++++++++++++- drivers/net/can/usb/esd_usb2.c | 16 +++++++++++++++- drivers/net/can/usb/usb_8dev.c | 15 +++++++++++++-- 3 files changed, 41 insertions(+), 4 deletions(-)
Signature · 1 line
2.32.0
PATCH 1/3 can: usb_8dev: fix memory leak
In usb_8dev_start() MAX_RX_URBS coherent buffers are allocated and there is nothing, that frees them:
1) In callback function the urb is resubmitted and that's all
2) In disconnect function urbs are simply killed, but URB_FREE_BUFFER is not set (see usb_8dev_start) and this flag cannot be used with coherent buffers.
So, all allocated buffers should be freed with usb_free_coherent() explicitly.
Side note: This code looks like a copy-paste of other can drivers. The same patch was applied to mcba_usb driver and it works nice with real hardware. There is no change in functionality, only clean-up code for coherent buffers
--- drivers/net/can/usb/usb_8dev.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
drivers/net/can/usb/usb_8dev.c +13 -2
@@ -137,7 +137,8 @@ struct usb_8dev_priv {u8 *cmd_msg_buffer;struct mutex usb_8dev_cmd_lock; - +void *rxbuf[MAX_RX_URBS ]; +dma_addr_t rxbuf_dma[MAX_RX_URBS ]; };/* tx frame */
@@ -733,6 +734,7 @@ static int usb_8dev_start(struct usb_8dev_priv *priv)for (i =0 ; i <MAX_RX_URBS ; i++) {struct urb *urb =NULL ;u8 *buf; +dma_addr_t buf_dma;/* create a URB, and a buffer for it */ urb =usb_alloc_urb (0 ,GFP_KERNEL );
@@ -742,7 +744,7 @@ static int usb_8dev_start(struct usb_8dev_priv *priv) } buf =usb_alloc_coherent (priv->udev,RX_BUFFER_SIZE ,GFP_KERNEL , - &urb->transfer_dma); + &buf_dma);if (!buf) {netdev_err (netdev,"No memory left for USB buffer\n" );usb_free_urb (urb);
@@ -750,6 +752,8 @@ static int usb_8dev_start(struct usb_8dev_priv *priv)break ; } + urb->transfer_dma = buf_dma; + usb_fill_bulk_urb(urb, priv->udev, usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_RX),
@@ -767,6 +771,9 @@ static int usb_8dev_start(struct usb_8dev_priv *priv)break ; } + priv->rxbuf[i] = buf; + priv->rxbuf_dma[i] = buf_dma; +/* Drop reference, USB core will take care of freeing it */ usb_free_urb (urb); }
@@ -836,6 +843,10 @@ static void unlink_all_urbs(struct usb_8dev_priv *priv)usb_kill_anchored_urbs (&priv->rx_submitted); +for (i =0 ; i <MAX_RX_URBS ; ++i) +usb_free_coherent (priv->udev,RX_BUFFER_SIZE , + priv->rxbuf[i], priv->rxbuf_dma[i]); +usb_kill_anchored_urbs (&priv->tx_submitted);atomic_set (&priv->active_tx_urbs,0 );
Signature · 1 line
2.32.0
PATCH 2/3 can: ems_usb: fix memory leak
In reply to Pavel SkripkinIn ems_usb_start() MAX_RX_URBS coherent buffers are allocated and there is nothing, that frees them:
1) In callback function the urb is resubmitted and that's all
2) In disconnect function urbs are simply killed, but URB_FREE_BUFFER is not set (see ems_usb_start) and this flag cannot be used with coherent buffers.
So, all allocated buffers should be freed with usb_free_coherent() explicitly.
Side note: This code looks like a copy-paste of other can drivers. The same patch was applied to mcba_usb driver and it works nice with real hardware. There is no change in functionality, only clean-up code for coherent buffers
--- drivers/net/can/usb/ems_usb.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/net/can/usb/ems_usb.c +13 -1
@@ -255,6 +255,8 @@ struct ems_usb {unsigned int free_slots;/* remember number of available slots */ struct ems_cpc_msg active_params;/* active controller parameters */ +void *rxbuf[MAX_RX_URBS ]; +dma_addr_t rxbuf_dma[MAX_RX_URBS ]; };static void ems_usb_read_interrupt_callback (struct urb *urb)
@@ -587,6 +589,7 @@ static int ems_usb_start(struct ems_usb *dev)for (i =0 ; i <MAX_RX_URBS ; i++) {struct urb *urb =NULL ;u8 *buf =NULL ; +dma_addr_t buf_dma;/* create a URB, and a buffer for it */ urb =usb_alloc_urb (0 ,GFP_KERNEL );
@@ -596,7 +599,7 @@ static int ems_usb_start(struct ems_usb *dev) } buf =usb_alloc_coherent (dev->udev,RX_BUFFER_SIZE ,GFP_KERNEL , - &urb->transfer_dma); + &buf_dma);if (!buf) {netdev_err (netdev,"No memory left for USB buffer\n" );usb_free_urb (urb);
@@ -604,6 +607,8 @@ static int ems_usb_start(struct ems_usb *dev)break ; } + urb->transfer_dma = buf_dma; +usb_fill_bulk_urb (urb, dev->udev,usb_rcvbulkpipe (dev->udev,2 ), buf,RX_BUFFER_SIZE , ems_usb_read_bulk_callback, dev);
@@ -619,6 +624,9 @@ static int ems_usb_start(struct ems_usb *dev)break ; } + dev->rxbuf[i] = buf; + dev->rxbuf_dma[i] = buf_dma; +/* Drop reference, USB core will take care of freeing it */ usb_free_urb (urb); }
@@ -684,6 +692,10 @@ static void unlink_all_urbs(struct ems_usb *dev)usb_kill_anchored_urbs (&dev->rx_submitted); +for (i =0 ; i <MAX_RX_URBS ; ++i) +usb_free_coherent (dev->udev,RX_BUFFER_SIZE , + dev->rxbuf[i], dev->rxbuf_dma[i]); +usb_kill_anchored_urbs (&dev->tx_submitted);atomic_set (&dev->active_tx_urbs,0 );
Signature · 1 line
2.32.0
PATCH 3/3 can: esd_usb2: fix memory leak
In reply to Pavel SkripkinIn esd_usb2_setup_rx_urbs() MAX_RX_URBS coherent buffers are allocated and there is nothing, that frees them:
1) In callback function the urb is resubmitted and that's all
2) In disconnect function urbs are simply killed, but URB_FREE_BUFFER is not set (see esd_usb2_setup_rx_urbs) and this flag cannot be used with coherent buffers.
So, all allocated buffers should be freed with usb_free_coherent() explicitly.
Side note: This code looks like a copy-paste of other can drivers. The same patch was applied to mcba_usb driver and it works nice with real hardware. There is no change in functionality, only clean-up code for coherent buffers
--- drivers/net/can/usb/esd_usb2.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
drivers/net/can/usb/esd_usb2.c +15 -1
@@ -195,6 +195,8 @@ struct esd_usb2 {int net_count;u32 version;int rxinitdone; +void *rxbuf[MAX_RX_URBS ]; +dma_addr_t rxbuf_dma[MAX_RX_URBS ]; };struct esd_usb2_net_priv {
@@ -545,6 +547,7 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)for (i =0 ; i <MAX_RX_URBS ; i++) {struct urb *urb =NULL ;u8 *buf =NULL ; +dma_addr_t buf_dma;/* create a URB, and a buffer for it */ urb =usb_alloc_urb (0 ,GFP_KERNEL );
@@ -554,7 +557,7 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev) } buf =usb_alloc_coherent (dev->udev,RX_BUFFER_SIZE ,GFP_KERNEL , - &urb->transfer_dma); + &buf_dma);if (!buf) {dev_warn (dev->udev->dev.parent,"No memory left for USB buffer\n" );
@@ -562,6 +565,8 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev) goto freeurb; } + urb->transfer_dma = buf_dma; + usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), buf, RX_BUFFER_SIZE,
@@ -574,8 +579,12 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)usb_unanchor_urb (urb);usb_free_coherent (dev->udev,RX_BUFFER_SIZE , buf, urb->transfer_dma); + goto freeusrb; } + dev->rxbuf[i] = buf; + dev->rxbuf_dma[i] = buf_dma; + freeurb:/* Drop reference, USB core will take care of freeing it */ usb_free_urb (urb);
@@ -663,6 +672,11 @@ static void unlink_all_urbs(struct esd_usb2 *dev)int i, j;usb_kill_anchored_urbs (&dev->rx_submitted); + +for (i =0 ; i <MAX_RX_URBS ; ++i) +usb_free_coherent (dev->udev,RX_BUFFER_SIZE , + dev->rxbuf[i], dev->rxbuf_dma[i]); +for (i =0 ; i < dev->net_count; i++) { priv = dev->nets[i];if (priv) {
Signature · 1 line
2.32.0
kernel test robot
build botRe: [PATCH 3/3] can: esd_usb2: fix memory leak
Thank you for the patch! Yet something to improve:
Hi Pavel,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on mkl-can-next/testing]
[also build test ERROR on v5.14-rc3 next-20210723]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Pavel-Skripkin/can-fix-same-memory-leaks-in-can-drivers/20210726-233224 base: https://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git testing config: sh-allmodconfig (attached as .config) compiler: sh4-linux-gcc (GCC) 10.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/14373e3834eb74f943720146607c709613b93e95
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Pavel-Skripkin/can-fix-same-memory-leaks-in-can-drivers/20210726-233224 git checkout 14373e3834eb74f943720146607c709613b93e95
# save the attached .config to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-10.3.0 make.cross O=build_dir ARCH=sh SHELL=/bin/bash drivers/net/can/usb/
If you fix the issue, kindly add following tag as appropriate
All errors (new ones prefixed by >>):
drivers/net/can/usb/esd_usb2.c: In function 'esd_usb2_setup_rx_urbs':
>> drivers/net/can/usb/esd_usb2.c:582:4: error: label 'freeusrb' used but not defined
582 | goto freeusrb;
| ^~~~Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for SND_ATMEL_SOC_PDC
Depends on SOUND && !UML && SND && SND_SOC && SND_ATMEL_SOC && HAS_DMA Selected by
- SND_ATMEL_SOC_SSC && SOUND && !UML && SND && SND_SOC && SND_ATMEL_SOC
- SND_ATMEL_SOC_SSC_PDC && SOUND && !UML && SND && SND_SOC && SND_ATMEL_SOC && ATMEL_SSC
vim +/freeusrb +582 drivers/net/can/usb/esd_usb2.c
539
540 static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
541 {
542 int i, err = 0;
543
544 if (dev->rxinitdone)
545 return 0;
546
547 for (i = 0; i < MAX_RX_URBS; i++) {
548 struct urb *urb = NULL;
549 u8 *buf = NULL;
550 dma_addr_t buf_dma;
551
552 /* create a URB, and a buffer for it */
553 urb = usb_alloc_urb(0, GFP_KERNEL);
554 if (!urb) {
555 err = -ENOMEM;
556 break;
557 }
558
559 buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,
560 &buf_dma);
561 if (!buf) {
562 dev_warn(dev->udev->dev.parent,
563 "No memory left for USB buffer\n");
564 err = -ENOMEM;
565 goto freeurb;
566 }
567
568 urb->transfer_dma = buf_dma;
569
570 usb_fill_bulk_urb(urb, dev->udev,
571 usb_rcvbulkpipe(dev->udev, 1),
572 buf, RX_BUFFER_SIZE,
573 esd_usb2_read_bulk_callback, dev);
574 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
575 usb_anchor_urb(urb, &dev->rx_submitted);
576
577 err = usb_submit_urb(urb, GFP_KERNEL);
578 if (err) {
579 usb_unanchor_urb(urb);
580 usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
581 urb->transfer_dma);
> 582 goto freeusrb; 583 }
584
585 dev->rxbuf[i] = buf;
586 dev->rxbuf_dma[i] = buf_dma;
587
588 freeurb:
589 /* Drop reference, USB core will take care of freeing it */
590 usb_free_urb(urb);
591 if (err)
592 break;
593 }
594
595 /* Did we submit any URBs */
596 if (i == 0) {
597 dev_err(dev->udev->dev.parent, "couldn't setup read URBs\n");
598 return err;
599 }
600
601 /* Warn if we've couldn't transmit all the URBs */
602 if (i < MAX_RX_URBS) {
603 dev_warn(dev->udev->dev.parent,
604 "rx performance may be slow\n");
605 }
606
607 dev->rxinitdone = 1;
608 return 0;
609 }
610
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
kernel test robot
build botRe: [PATCH 3/3] can: esd_usb2: fix memory leak
In reply to Pavel SkripkinThank you for the patch! Yet something to improve:
Hi Pavel,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on mkl-can-next/testing]
[also build test ERROR on v5.14-rc3 next-20210727]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Pavel-Skripkin/can-fix-same-memory-leaks-in-can-drivers/20210726-233224 base: https://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git testing config: x86_64-randconfig-a012-20210728 (attached as .config) compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project c49df15c278857adecd12db6bb1cdc96885f7079)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/14373e3834eb74f943720146607c709613b93e95
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Pavel-Skripkin/can-fix-same-memory-leaks-in-can-drivers/20210726-233224 git checkout 14373e3834eb74f943720146607c709613b93e95
# save the attached .config to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross O=build_dir ARCH=x86_64 SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate
All errors (new ones prefixed by >>):
>> drivers/net/can/usb/esd_usb2.c:582:9: error: use of undeclared label 'freeusrb'
goto freeusrb;
^1 error generated.
vim +/freeusrb +582 drivers/net/can/usb/esd_usb2.c
539
540 static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
541 {
542 int i, err = 0;
543
544 if (dev->rxinitdone)
545 return 0;
546
547 for (i = 0; i < MAX_RX_URBS; i++) {
548 struct urb *urb = NULL;
549 u8 *buf = NULL;
550 dma_addr_t buf_dma;
551
552 /* create a URB, and a buffer for it */
553 urb = usb_alloc_urb(0, GFP_KERNEL);
554 if (!urb) {
555 err = -ENOMEM;
556 break;
557 }
558
559 buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE, GFP_KERNEL,
560 &buf_dma);
561 if (!buf) {
562 dev_warn(dev->udev->dev.parent,
563 "No memory left for USB buffer\n");
564 err = -ENOMEM;
565 goto freeurb;
566 }
567
568 urb->transfer_dma = buf_dma;
569
570 usb_fill_bulk_urb(urb, dev->udev,
571 usb_rcvbulkpipe(dev->udev, 1),
572 buf, RX_BUFFER_SIZE,
573 esd_usb2_read_bulk_callback, dev);
574 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
575 usb_anchor_urb(urb, &dev->rx_submitted);
576
577 err = usb_submit_urb(urb, GFP_KERNEL);
578 if (err) {
579 usb_unanchor_urb(urb);
580 usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
581 urb->transfer_dma);
> 582 goto freeusrb; 583 }
584
585 dev->rxbuf[i] = buf;
586 dev->rxbuf_dma[i] = buf_dma;
587
588 freeurb:
589 /* Drop reference, USB core will take care of freeing it */
590 usb_free_urb(urb);
591 if (err)
592 break;
593 }
594
595 /* Did we submit any URBs */
596 if (i == 0) {
597 dev_err(dev->udev->dev.parent, "couldn't setup read URBs\n");
598 return err;
599 }
600
601 /* Warn if we've couldn't transmit all the URBs */
602 if (i < MAX_RX_URBS) {
603 dev_warn(dev->udev->dev.parent,
604 "rx performance may be slow\n");
605 }
606
607 dev->rxinitdone = 1;
608 return 0;
609 }
610
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
Quoted 2 lines · On Mon, 26 Jul 2021 18:29:38 +0300 Pavel Skripkin <[email protected]> wrote:
Hi, Marc and can drivers maintainers/reviewers!
I reread this I found out, that I missed logic here.
I mean:
Quoted 3 lines
A long time ago syzbot reported memory leak in
mcba_usbcan driver[1]. It was using strange pattern for allocating coherent buffers, which was leading to memory leaks.
I fixed this wrong pattern in mcba_usb driver and
Quoted 28 lines
Yesterday I got a report,
thatmcba_usbstopped working since my commit. I came up with quick fix and all started working well.There are at least 3 more drivers with this pattern, I decided to fix leaks in them too, since code is actually the same (I guess, driver authors just copy pasted code parts). Each of following patches is combination of
91c02557174b("can:mcba_usb: fix memory leak inmcba_usb") and my yesterday fix [2].Dear maintainers/reviewers, if You have one of these hardware pieces, please, test these patches and report any errors you will find.
[1]
https://syzkaller.appspot.com/bug?id=c94c1c23e829d5ac97995d51219f0c5a0cd1fa54
[2]
https://lore.kernel.org/netdev/[email protected]/With regards,
Pavel SkripkinPavel Skripkin (3):
can:usb_8dev: fix memory leak
can:ems_usb: fix memory leak
can:esd_usb2: fix memory leak
Quoted 5 lines
drivers/net/can/usb/ems_usb.c | 14 +++++++++++++- drivers/net/can/usb/esd_usb2.c | 16 +++++++++++++++- drivers/net/can/usb/usb_8dev.c | 15 +++++++++++++-- 3 files changed, 41 insertions(+), 4 deletions(-)
With regards,
Pavel Skripkin
Marc Kleine-Budde
maintainerQuoted 8 lines · Pavel Skripkin
Quoted 2 lines · On Mon, 26 Jul 2021 18:29:38 +0300 Pavel Skripkin <[email protected]> wrote:
Hi, Marc and can drivers maintainers/reviewers!
I reread this I found out, that I missed logic here.
Quoted 7 lines
I mean:
Quoted 3 lines
A long time ago syzbot reported memory leak in
mcba_usbcan driver[1]. It was using strange pattern for allocating coherent buffers, which was leading to memory leaks.I fixed this wrong pattern in
mcba_usbdriver and
Thanks for your patches! Please resend them with an updated description and the fixed patch 3.
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Embedded Linux | https://www.pengutronix.de | Vertretung West/Dortmund | Phone: +49-231-2826-924 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
v2 cover can: fix same memory leaks in can drivers
In reply to Pavel SkripkinHi, Marc and can drivers maintainers/reviewers!
A long time ago syzbot reported memory leak in mcba_usb can driver[1]. It was using strange pattern for allocating coherent buffers, which was leading to memory leaks. I fixed this wrong pattern in mcba_usb driver and yesterday I got a report, that mcba_usb stopped working since my commit. I came up with quick fix and all started working well.
There are at least 3 more drivers with this pattern, I decided to fix leaks in them too, since code is actually the same (I guess, driver authors just copy pasted code parts). Each of following patches is combination of 91c02557174b ("can: mcba_usb: fix memory leak in mcba_usb") and my yesterday fix [2].
Dear maintainers/reviewers, if You have one of these hardware pieces, please, test these patches and report any errors you will find.
[1] https://syzkaller.appspot.com/bug?id=c94c1c23e829d5ac97995d51219f0c5a0cd1fa54
[2] https://lore.kernel.org/netdev/[email protected]/
v1 -> v2
Fixed compilation error in 3rd patch
Fixed cover letter
With regards,
Pavel Skripkin
Pavel Skripkin (3):
can: usb_8dev: fix memory leak
can: ems_usb: fix memory leak
can: esd_usb2: fix memory leak
drivers/net/can/usb/ems_usb.c | 14 +++++++++++++- drivers/net/can/usb/esd_usb2.c | 16 +++++++++++++++- drivers/net/can/usb/usb_8dev.c | 15 +++++++++++++-- 3 files changed, 41 insertions(+), 4 deletions(-)
Signature · 1 line
2.32.0
PATCH v2 1/3 can: usb_8dev: fix memory leak
In usb_8dev_start() MAX_RX_URBS coherent buffers are allocated and there is nothing, that frees them:
1) In callback function the urb is resubmitted and that's all
2) In disconnect function urbs are simply killed, but URB_FREE_BUFFER is not set (see usb_8dev_start) and this flag cannot be used with coherent buffers.
So, all allocated buffers should be freed with usb_free_coherent() explicitly.
Side note: This code looks like a copy-paste of other can drivers. The same patch was applied to mcba_usb driver and it works nice with real hardware. There is no change in functionality, only clean-up code for coherent buffers
--- drivers/net/can/usb/usb_8dev.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
drivers/net/can/usb/usb_8dev.c +13 -2
@@ -137,7 +137,8 @@ struct usb_8dev_priv {u8 *cmd_msg_buffer;struct mutex usb_8dev_cmd_lock; - +void *rxbuf[MAX_RX_URBS ]; +dma_addr_t rxbuf_dma[MAX_RX_URBS ]; };/* tx frame */
@@ -733,6 +734,7 @@ static int usb_8dev_start(struct usb_8dev_priv *priv)for (i =0 ; i <MAX_RX_URBS ; i++) {struct urb *urb =NULL ;u8 *buf; +dma_addr_t buf_dma;/* create a URB, and a buffer for it */ urb =usb_alloc_urb (0 ,GFP_KERNEL );
@@ -742,7 +744,7 @@ static int usb_8dev_start(struct usb_8dev_priv *priv) } buf =usb_alloc_coherent (priv->udev,RX_BUFFER_SIZE ,GFP_KERNEL , - &urb->transfer_dma); + &buf_dma);if (!buf) {netdev_err (netdev,"No memory left for USB buffer\n" );usb_free_urb (urb);
@@ -750,6 +752,8 @@ static int usb_8dev_start(struct usb_8dev_priv *priv)break ; } + urb->transfer_dma = buf_dma; + usb_fill_bulk_urb(urb, priv->udev, usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_RX),
@@ -767,6 +771,9 @@ static int usb_8dev_start(struct usb_8dev_priv *priv)break ; } + priv->rxbuf[i] = buf; + priv->rxbuf_dma[i] = buf_dma; +/* Drop reference, USB core will take care of freeing it */ usb_free_urb (urb); }
@@ -836,6 +843,10 @@ static void unlink_all_urbs(struct usb_8dev_priv *priv)usb_kill_anchored_urbs (&priv->rx_submitted); +for (i =0 ; i <MAX_RX_URBS ; ++i) +usb_free_coherent (priv->udev,RX_BUFFER_SIZE , + priv->rxbuf[i], priv->rxbuf_dma[i]); +usb_kill_anchored_urbs (&priv->tx_submitted);atomic_set (&priv->active_tx_urbs,0 );
Signature · 1 line
2.32.0
PATCH v2 2/3 can: ems_usb: fix memory leak
In reply to Pavel SkripkinIn ems_usb_start() MAX_RX_URBS coherent buffers are allocated and there is nothing, that frees them:
1) In callback function the urb is resubmitted and that's all
2) In disconnect function urbs are simply killed, but URB_FREE_BUFFER is not set (see ems_usb_start) and this flag cannot be used with coherent buffers.
So, all allocated buffers should be freed with usb_free_coherent() explicitly.
Side note: This code looks like a copy-paste of other can drivers. The same patch was applied to mcba_usb driver and it works nice with real hardware. There is no change in functionality, only clean-up code for coherent buffers
--- drivers/net/can/usb/ems_usb.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/net/can/usb/ems_usb.c +13 -1
@@ -255,6 +255,8 @@ struct ems_usb {unsigned int free_slots;/* remember number of available slots */ struct ems_cpc_msg active_params;/* active controller parameters */ +void *rxbuf[MAX_RX_URBS ]; +dma_addr_t rxbuf_dma[MAX_RX_URBS ]; };static void ems_usb_read_interrupt_callback (struct urb *urb)
@@ -587,6 +589,7 @@ static int ems_usb_start(struct ems_usb *dev)for (i =0 ; i <MAX_RX_URBS ; i++) {struct urb *urb =NULL ;u8 *buf =NULL ; +dma_addr_t buf_dma;/* create a URB, and a buffer for it */ urb =usb_alloc_urb (0 ,GFP_KERNEL );
@@ -596,7 +599,7 @@ static int ems_usb_start(struct ems_usb *dev) } buf =usb_alloc_coherent (dev->udev,RX_BUFFER_SIZE ,GFP_KERNEL , - &urb->transfer_dma); + &buf_dma);if (!buf) {netdev_err (netdev,"No memory left for USB buffer\n" );usb_free_urb (urb);
@@ -604,6 +607,8 @@ static int ems_usb_start(struct ems_usb *dev)break ; } + urb->transfer_dma = buf_dma; +usb_fill_bulk_urb (urb, dev->udev,usb_rcvbulkpipe (dev->udev,2 ), buf,RX_BUFFER_SIZE , ems_usb_read_bulk_callback, dev);
@@ -619,6 +624,9 @@ static int ems_usb_start(struct ems_usb *dev)break ; } + dev->rxbuf[i] = buf; + dev->rxbuf_dma[i] = buf_dma; +/* Drop reference, USB core will take care of freeing it */ usb_free_urb (urb); }
@@ -684,6 +692,10 @@ static void unlink_all_urbs(struct ems_usb *dev)usb_kill_anchored_urbs (&dev->rx_submitted); +for (i =0 ; i <MAX_RX_URBS ; ++i) +usb_free_coherent (dev->udev,RX_BUFFER_SIZE , + dev->rxbuf[i], dev->rxbuf_dma[i]); +usb_kill_anchored_urbs (&dev->tx_submitted);atomic_set (&dev->active_tx_urbs,0 );
Signature · 1 line
2.32.0
PATCH v2 3/3 can: esd_usb2: fix memory leak
In reply to Pavel SkripkinIn esd_usb2_setup_rx_urbs() MAX_RX_URBS coherent buffers are allocated and there is nothing, that frees them:
1) In callback function the urb is resubmitted and that's all
2) In disconnect function urbs are simply killed, but URB_FREE_BUFFER is not set (see esd_usb2_setup_rx_urbs) and this flag cannot be used with coherent buffers.
So, all allocated buffers should be freed with usb_free_coherent() explicitly.
Side note: This code looks like a copy-paste of other can drivers. The same patch was applied to mcba_usb driver and it works nice with real hardware. There is no change in functionality, only clean-up code for coherent buffers
--- drivers/net/can/usb/esd_usb2.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
drivers/net/can/usb/esd_usb2.c +15 -1
@@ -195,6 +195,8 @@ struct esd_usb2 {int net_count;u32 version;int rxinitdone; +void *rxbuf[MAX_RX_URBS ]; +dma_addr_t rxbuf_dma[MAX_RX_URBS ]; };struct esd_usb2_net_priv {
@@ -545,6 +547,7 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)for (i =0 ; i <MAX_RX_URBS ; i++) {struct urb *urb =NULL ;u8 *buf =NULL ; +dma_addr_t buf_dma;/* create a URB, and a buffer for it */ urb =usb_alloc_urb (0 ,GFP_KERNEL );
@@ -554,7 +557,7 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev) } buf =usb_alloc_coherent (dev->udev,RX_BUFFER_SIZE ,GFP_KERNEL , - &urb->transfer_dma); + &buf_dma);if (!buf) {dev_warn (dev->udev->dev.parent,"No memory left for USB buffer\n" );
@@ -562,6 +565,8 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev) goto freeurb; } + urb->transfer_dma = buf_dma; + usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), buf, RX_BUFFER_SIZE,
@@ -574,8 +579,12 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)usb_unanchor_urb (urb);usb_free_coherent (dev->udev,RX_BUFFER_SIZE , buf, urb->transfer_dma); + goto freeurb; } + dev->rxbuf[i] = buf; + dev->rxbuf_dma[i] = buf_dma; + freeurb:/* Drop reference, USB core will take care of freeing it */ usb_free_urb (urb);
@@ -663,6 +672,11 @@ static void unlink_all_urbs(struct esd_usb2 *dev)int i, j;usb_kill_anchored_urbs (&dev->rx_submitted); + +for (i =0 ; i <MAX_RX_URBS ; ++i) +usb_free_coherent (dev->udev,RX_BUFFER_SIZE , + dev->rxbuf[i], dev->rxbuf_dma[i]); +for (i =0 ; i < dev->net_count; i++) { priv = dev->nets[i];if (priv) {
Signature · 1 line
2.32.0
Marc Kleine-Budde
maintainerQuoted 8 lines · Pavel Skripkin
Hi, Marc and can drivers maintainers/reviewers!
A long time ago syzbot reported memory leak in
mcba_usbcan driver[1]. It was using strange pattern for allocating coherent buffers, which was leading to memory leaks. I fixed this wrong pattern inmcba_usbdriver and yesterday I got a report, thatmcba_usbstopped working since my commit. I came up with quick fix and all started working well.
Quoted 8 lines
There are at least 3 more drivers with this pattern, I decided to fix leaks in them too, since code is actually the same (I guess, driver authors just copy pasted code parts). Each of following patches is combination of
91c02557174b("can:mcba_usb: fix memory leak inmcba_usb") and my yesterday fix [2].Dear maintainers/reviewers, if You have one of these hardware pieces, please, test these patches and report any errors you will find.
Added to linux-can-next/testing.
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Embedded Linux | https://www.pengutronix.de | Vertretung West/Dortmund | Phone: +49-231-2826-924 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |