lkml.org 
[lkml]   [2019]   [Oct]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.19 097/106] xen-netfront: do not use ~0U as error return value for xennet_fill_frags()
    Date
    From: Dongli Zhang <dongli.zhang@oracle.com>

    [ Upstream commit a761129e3625688310aecf26e1be9e98e85f8eb5 ]

    xennet_fill_frags() uses ~0U as return value when the sk_buff is not able
    to cache extra fragments. This is incorrect because the return type of
    xennet_fill_frags() is RING_IDX and 0xffffffff is an expected value for
    ring buffer index.

    In the situation when the rsp_cons is approaching 0xffffffff, the return
    value of xennet_fill_frags() may become 0xffffffff which xennet_poll() (the
    caller) would regard as error. As a result, queue->rx.rsp_cons is set
    incorrectly because it is updated only when there is error. If there is no
    error, xennet_poll() would be responsible to update queue->rx.rsp_cons.
    Finally, queue->rx.rsp_cons would point to the rx ring buffer entries whose
    queue->rx_skbs[i] and queue->grant_rx_ref[i] are already cleared to NULL.
    This leads to NULL pointer access in the next iteration to process rx ring
    buffer entries.

    The symptom is similar to the one fixed in
    commit 00b368502d18 ("xen-netfront: do not assume sk_buff_head list is
    empty in error handling").

    This patch changes the return type of xennet_fill_frags() to indicate
    whether it is successful or failed. The queue->rx.rsp_cons will be
    always updated inside this function.

    Fixes: ad4f15dc2c70 ("xen/netfront: don't bug in case of too many frags")
    Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com>
    Reviewed-by: Juergen Gross <jgross@suse.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/net/xen-netfront.c | 17 +++++++++--------
    1 file changed, 9 insertions(+), 8 deletions(-)

    --- a/drivers/net/xen-netfront.c
    +++ b/drivers/net/xen-netfront.c
    @@ -890,9 +890,9 @@ static int xennet_set_skb_gso(struct sk_
    return 0;
    }

    -static RING_IDX xennet_fill_frags(struct netfront_queue *queue,
    - struct sk_buff *skb,
    - struct sk_buff_head *list)
    +static int xennet_fill_frags(struct netfront_queue *queue,
    + struct sk_buff *skb,
    + struct sk_buff_head *list)
    {
    RING_IDX cons = queue->rx.rsp_cons;
    struct sk_buff *nskb;
    @@ -911,7 +911,7 @@ static RING_IDX xennet_fill_frags(struct
    if (unlikely(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) {
    queue->rx.rsp_cons = ++cons + skb_queue_len(list);
    kfree_skb(nskb);
    - return ~0U;
    + return -ENOENT;
    }

    skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags,
    @@ -922,7 +922,9 @@ static RING_IDX xennet_fill_frags(struct
    kfree_skb(nskb);
    }

    - return cons;
    + queue->rx.rsp_cons = cons;
    +
    + return 0;
    }

    static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
    @@ -1048,8 +1050,7 @@ err:
    skb->data_len = rx->status;
    skb->len += rx->status;

    - i = xennet_fill_frags(queue, skb, &tmpq);
    - if (unlikely(i == ~0U))
    + if (unlikely(xennet_fill_frags(queue, skb, &tmpq)))
    goto err;

    if (rx->flags & XEN_NETRXF_csum_blank)
    @@ -1059,7 +1060,7 @@ err:

    __skb_queue_tail(&rxq, skb);

    - queue->rx.rsp_cons = ++i;
    + i = ++queue->rx.rsp_cons;
    work_done++;
    }


    \
     
     \ /
      Last update: 2019-10-06 19:59    [W:5.590 / U:1.272 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site