On Thu, Jun 26, 2025 at 12:10 AM Bui Quang Minh <minhquangbu...@gmail.com> wrote: > > In xdp_linearize_page, when reading the following buffers from the ring, > we forget to check the received length with the true allocate size. This > can lead to an out-of-bound read. This commit adds that missing check. > > Fixes: 4941d472bf95 ("virtio-net: do not reset during XDP set")
I think we should cc stable. > Signed-off-by: Bui Quang Minh <minhquangbu...@gmail.com> > --- > drivers/net/virtio_net.c | 27 ++++++++++++++++++++++----- > 1 file changed, 22 insertions(+), 5 deletions(-) > > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c > index e53ba600605a..2a130a3e50ac 100644 > --- a/drivers/net/virtio_net.c > +++ b/drivers/net/virtio_net.c > @@ -1797,7 +1797,8 @@ static unsigned int virtnet_get_headroom(struct > virtnet_info *vi) > * across multiple buffers (num_buf > 1), and we make sure buffers > * have enough headroom. > */ > -static struct page *xdp_linearize_page(struct receive_queue *rq, > +static struct page *xdp_linearize_page(struct net_device *dev, > + struct receive_queue *rq, > int *num_buf, > struct page *p, > int offset, > @@ -1818,17 +1819,33 @@ static struct page *xdp_linearize_page(struct > receive_queue *rq, > page_off += *len; > > while (--*num_buf) { > - unsigned int buflen; > + unsigned int headroom, tailroom, room; > + unsigned int truesize, buflen; > void *buf; > + void *ctx; > int off; > > - buf = virtnet_rq_get_buf(rq, &buflen, NULL); > + buf = virtnet_rq_get_buf(rq, &buflen, &ctx); > if (unlikely(!buf)) > goto err_buf; > > p = virt_to_head_page(buf); > off = buf - page_address(p); > > + truesize = mergeable_ctx_to_truesize(ctx); This won't work for receive_small_xdp(). > + headroom = mergeable_ctx_to_headroom(ctx); > + tailroom = headroom ? sizeof(struct skb_shared_info) : 0; > + room = SKB_DATA_ALIGN(headroom + tailroom); > + > + if (unlikely(buflen > truesize - room)) { > + put_page(p); > + pr_debug("%s: rx error: len %u exceeds truesize > %lu\n", > + dev->name, buflen, > + (unsigned long)(truesize - room)); > + DEV_STATS_INC(dev, rx_length_errors); > + goto err_buf; > + } I wonder if this issue only affect XDP should we check other places? > + > /* guard against a misconfigured or uncooperative backend that > * is sending packet larger than the MTU. > */ > @@ -1917,7 +1934,7 @@ static struct sk_buff *receive_small_xdp(struct > net_device *dev, > headroom = vi->hdr_len + header_offset; > buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) + > SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); > - xdp_page = xdp_linearize_page(rq, &num_buf, page, > + xdp_page = xdp_linearize_page(dev, rq, &num_buf, page, > offset, header_offset, > &tlen); > if (!xdp_page) > @@ -2252,7 +2269,7 @@ static void *mergeable_xdp_get_buf(struct virtnet_info > *vi, > */ > if (!xdp_prog->aux->xdp_has_frags) { > /* linearize data for XDP */ > - xdp_page = xdp_linearize_page(rq, num_buf, > + xdp_page = xdp_linearize_page(vi->dev, rq, num_buf, > *page, offset, > XDP_PACKET_HEADROOM, > len); > -- > 2.43.0 >