diff mbox

brcmfmac: Fix glob_skb leak in brcmf_sdiod_recv_chain

Message ID 1496424146-10928-1-git-send-email-housel@acm.org (mailing list archive)
State Changes Requested
Delegated to: Kalle Valo
Headers show

Commit Message

Peter S. Housel June 2, 2017, 5:22 p.m. UTC
An earlier change to this function (3bdae810721b) fixed a leak in the
case of an unsuccessful call to brcmf_sdiod_buffrw(). However, the
glob_skb buffer, used for emulating a scattering read, is never used
or referenced after its contents are copied into the destination
buffers, and therefore always needs to be freed by the end of the
function.

Signed-off-by: Peter S. Housel <housel@acm.org>
---
 drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

Comments

Florian Fainelli June 2, 2017, 6:48 p.m. UTC | #1
On 06/02/2017 10:22 AM, Peter S. Housel wrote:
> An earlier change to this function (3bdae810721b) fixed a leak in the
> case of an unsuccessful call to brcmf_sdiod_buffrw(). However, the
> glob_skb buffer, used for emulating a scattering read, is never used
> or referenced after its contents are copied into the destination
> buffers, and therefore always needs to be freed by the end of the
> function.

That looks correct, could you add the relevant Fixes tag for this?

Fixes: 3bdae810721b ("brcmfmac: Fix glob_skb leak in
brcmf_sdiod_recv_chain")
Fixes: a413e39a38573 ("brcmfmac: fix brcmf_sdcard_recv_chain() for host
without sg support")

BTW, you made the same typo that I did, it's actually glom_skb ;)

> 
> Signed-off-by: Peter S. Housel <housel@acm.org>
> ---
>  drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
> index 9b970dc..4c5064f 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
> @@ -727,15 +727,16 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
>  			return -ENOMEM;
>  		err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
>  					 glom_skb);
> -		if (err) {
> -			brcmu_pkt_buf_free_skb(glom_skb);
> -			goto done;
> -		}
> +		if (err)
> +			goto free_glom_skb;
>  
>  		skb_queue_walk(pktq, skb) {
>  			memcpy(skb->data, glom_skb->data, skb->len);
>  			skb_pull(glom_skb, skb->len);
>  		}
> +
> +free_glom_skb:
> +		brcmu_pkt_buf_free_skb(glom_skb);
>  	} else
>  		err = brcmf_sdiod_sglist_rw(sdiodev, SDIO_FUNC_2, false, addr,
>  					    pktq);
>
Franky Lin June 2, 2017, 6:52 p.m. UTC | #2
On Fri, Jun 2, 2017 at 10:22 AM, Peter S. Housel <housel@acm.org> wrote:
> An earlier change to this function (3bdae810721b) fixed a leak in the
> case of an unsuccessful call to brcmf_sdiod_buffrw(). However, the
> glob_skb buffer, used for emulating a scattering read, is never used
> or referenced after its contents are copied into the destination
> buffers, and therefore always needs to be freed by the end of the
> function.
>
> Signed-off-by: Peter S. Housel <housel@acm.org>
> ---
>  drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
> index 9b970dc..4c5064f 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
> @@ -727,15 +727,16 @@ int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
>                         return -ENOMEM;
>                 err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
>                                          glom_skb);
> -               if (err) {
> -                       brcmu_pkt_buf_free_skb(glom_skb);
> -                       goto done;
> -               }
> +               if (err)
> +                       goto free_glom_skb;
>
>                 skb_queue_walk(pktq, skb) {
>                         memcpy(skb->data, glom_skb->data, skb->len);
>                         skb_pull(glom_skb, skb->len);
>                 }
> +
> +free_glom_skb:
> +               brcmu_pkt_buf_free_skb(glom_skb);

What about
        if (!err) {
            skb_queue_walk(pktq, skb) {
                memcpy(skb->data, glom_skb->data, skb->len);
                skb_pull(glom_skb, skb->len);
            }
        }
        brcmu_pkt_buf_free_skb(glom_skb);

Then no goto is needed.

Thanks,
Franky

>         } else
>                 err = brcmf_sdiod_sglist_rw(sdiodev, SDIO_FUNC_2, false, addr,
>                                             pktq);
> --
> 2.7.4
>
Andy Shevchenko June 3, 2017, 3:46 p.m. UTC | #3
On Fri, Jun 2, 2017 at 9:52 PM, Franky Lin <franky.lin@broadcom.com> wrote:
> On Fri, Jun 2, 2017 at 10:22 AM, Peter S. Housel <housel@acm.org> wrote:

>>                 err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
>>                                          glom_skb);
>> -               if (err) {
>> -                       brcmu_pkt_buf_free_skb(glom_skb);
>> -                       goto done;
>> -               }

> What about
>         if (!err) {
>             skb_queue_walk(pktq, skb) {
>                 memcpy(skb->data, glom_skb->data, skb->len);
>                 skb_pull(glom_skb, skb->len);
>             }
>         }
>         brcmu_pkt_buf_free_skb(glom_skb);
>
> Then no goto is needed.

For my point of view it has two subtle inconveniences:
1. Not so usual pattern in use if (!ret)
2. Less error prone in case someone decides to expand the code and
missed ! or something else there.

Since both makes an approach less error prone I wouldn't suggest doing
that as I commented in new version.
diff mbox

Patch

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
index 9b970dc..4c5064f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -727,15 +727,16 @@  int brcmf_sdiod_recv_chain(struct brcmf_sdio_dev *sdiodev,
 			return -ENOMEM;
 		err = brcmf_sdiod_buffrw(sdiodev, SDIO_FUNC_2, false, addr,
 					 glom_skb);
-		if (err) {
-			brcmu_pkt_buf_free_skb(glom_skb);
-			goto done;
-		}
+		if (err)
+			goto free_glom_skb;
 
 		skb_queue_walk(pktq, skb) {
 			memcpy(skb->data, glom_skb->data, skb->len);
 			skb_pull(glom_skb, skb->len);
 		}
+
+free_glom_skb:
+		brcmu_pkt_buf_free_skb(glom_skb);
 	} else
 		err = brcmf_sdiod_sglist_rw(sdiodev, SDIO_FUNC_2, false, addr,
 					    pktq);