Re: [PATCH for-next] RDMA/rxe: Fix coding error in rxe_rcv_mcast_pkt

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Jan 28, 2021 at 9:12 AM Bob Pearson <rpearsonhpe@xxxxxxxxx> wrote:
>
> rxe_rcv_mcast_pkt() in rxe_recv.c can leak SKBs in error path
> code. The loop over the QPs attached to a multicast group
> creates new cloned SKBs for all but the last QP in the list
> and passes the SKB and its clones to rxe_rcv_pkt() for further
> processing. Any QPs that do not pass some checks are skipped.
> If the last QP in the list fails the tests the SKB is leaked.
> This patch checks if the SKB for the last QP was used and if
> not frees it. Also removes a redundant loop invariant assignment.
>
> Fixes: 8700e3e7c4857 ("Soft RoCE driver")
> Fixes: 71abf20b28ff8 ("RDMA/rxe: Handle skb_clone() failure in rxe_recv.c")
> Signed-off-by: Bob Pearson <rpearson@xxxxxxx>
> ---
>  drivers/infiniband/sw/rxe/rxe_recv.c | 18 +++++++++++-------
>  1 file changed, 11 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/infiniband/sw/rxe/rxe_recv.c b/drivers/infiniband/sw/rxe/rxe_recv.c
> index c9984a28eecc..57cc25e3b4ad 100644
> --- a/drivers/infiniband/sw/rxe/rxe_recv.c
> +++ b/drivers/infiniband/sw/rxe/rxe_recv.c
> @@ -252,7 +252,6 @@ static void rxe_rcv_mcast_pkt(struct rxe_dev *rxe, struct sk_buff *skb)
>
>         list_for_each_entry(mce, &mcg->qp_list, qp_list) {
>                 qp = mce->qp;
> -               pkt = SKB_TO_PKT(skb);
>
>                 /* validate qp for incoming packet */
>                 err = check_type_state(rxe, pkt, qp);
> @@ -264,12 +263,18 @@ static void rxe_rcv_mcast_pkt(struct rxe_dev *rxe, struct sk_buff *skb)
>                         continue;
>
>                 /* for all but the last qp create a new clone of the
> -                * skb and pass to the qp.
> +                * skb and pass to the qp. If an error occurs in the
> +                * checks for the last qp in the list we need to
> +                * free the skb since it hasn't been passed on to
> +                * rxe_rcv_pkt() which would free it later.
>                  */
> -               if (mce->qp_list.next != &mcg->qp_list)
> +               if (mce->qp_list.next != &mcg->qp_list) {
>                         per_qp_skb = skb_clone(skb, GFP_ATOMIC);
> -               else
> +               } else {
>                         per_qp_skb = skb;
> +                       /* show we have consumed the skb */
> +                       skb = NULL;
> +               }
>
>                 if (unlikely(!per_qp_skb))
>                         continue;
> @@ -284,10 +289,9 @@ static void rxe_rcv_mcast_pkt(struct rxe_dev *rxe, struct sk_buff *skb)
>
>         rxe_drop_ref(mcg);      /* drop ref from rxe_pool_get_key. */
>
> -       return;
> -
>  err1:
> -       kfree_skb(skb);
> +       if (skb)
> +               kfree_skb(skb);

"if (skb)" is not needed here.

The implemetation of kfree_skb:

void kfree_skb(struct sk_buff *skb)
{
if (unlikely(!skb))
return;
if (likely(atomic_read(&skb->users) == 1))
smp_rmb();
else if (likely(!atomic_dec_and_test(&skb->users)))
return;
trace_kfree_skb(skb, __builtin_return_address(0));
__kfree_skb(skb);
}

Zhu Yanjun
>  }
>
>  /**
> --
> 2.27.0
>



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux