Skip to content

Commit 6aca3da

Browse files
minhbq-99gregkh
authored andcommitted
virtio-net: ensure the received length does not exceed allocated size
[ Upstream commit 315dbdd7cdf6aa533829774caaf4d25f1fd20e73 ] 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. Cc: <[email protected]> Fixes: 4941d47 ("virtio-net: do not reset during XDP set") Signed-off-by: Bui Quang Minh <[email protected]> Acked-by: Jason Wang <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 100040b commit 6aca3da

File tree

1 file changed

+34
-4
lines changed

1 file changed

+34
-4
lines changed

drivers/net/virtio_net.c

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,26 @@ static unsigned int mergeable_ctx_to_truesize(void *mrg_ctx)
440440
return (unsigned long)mrg_ctx & ((1 << MRG_CTX_HEADER_SHIFT) - 1);
441441
}
442442

443+
static int check_mergeable_len(struct net_device *dev, void *mrg_ctx,
444+
unsigned int len)
445+
{
446+
unsigned int headroom, tailroom, room, truesize;
447+
448+
truesize = mergeable_ctx_to_truesize(mrg_ctx);
449+
headroom = mergeable_ctx_to_headroom(mrg_ctx);
450+
tailroom = headroom ? sizeof(struct skb_shared_info) : 0;
451+
room = SKB_DATA_ALIGN(headroom + tailroom);
452+
453+
if (len > truesize - room) {
454+
pr_debug("%s: rx error: len %u exceeds truesize %lu\n",
455+
dev->name, len, (unsigned long)(truesize - room));
456+
DEV_STATS_INC(dev, rx_length_errors);
457+
return -1;
458+
}
459+
460+
return 0;
461+
}
462+
443463
/* Called from bottom half context */
444464
static struct sk_buff *page_to_skb(struct virtnet_info *vi,
445465
struct receive_queue *rq,
@@ -719,7 +739,8 @@ static unsigned int virtnet_get_headroom(struct virtnet_info *vi)
719739
* across multiple buffers (num_buf > 1), and we make sure buffers
720740
* have enough headroom.
721741
*/
722-
static struct page *xdp_linearize_page(struct receive_queue *rq,
742+
static struct page *xdp_linearize_page(struct net_device *dev,
743+
struct receive_queue *rq,
723744
u16 *num_buf,
724745
struct page *p,
725746
int offset,
@@ -739,18 +760,27 @@ static struct page *xdp_linearize_page(struct receive_queue *rq,
739760
memcpy(page_address(page) + page_off, page_address(p) + offset, *len);
740761
page_off += *len;
741762

763+
/* Only mergeable mode can go inside this while loop. In small mode,
764+
* *num_buf == 1, so it cannot go inside.
765+
*/
742766
while (--*num_buf) {
743767
unsigned int buflen;
744768
void *buf;
769+
void *ctx;
745770
int off;
746771

747-
buf = virtqueue_get_buf(rq->vq, &buflen);
772+
buf = virtqueue_get_buf_ctx(rq->vq, &buflen, &ctx);
748773
if (unlikely(!buf))
749774
goto err_buf;
750775

751776
p = virt_to_head_page(buf);
752777
off = buf - page_address(p);
753778

779+
if (check_mergeable_len(dev, ctx, buflen)) {
780+
put_page(p);
781+
goto err_buf;
782+
}
783+
754784
/* guard against a misconfigured or uncooperative backend that
755785
* is sending packet larger than the MTU.
756786
*/
@@ -831,7 +861,7 @@ static struct sk_buff *receive_small(struct net_device *dev,
831861
headroom = vi->hdr_len + header_offset;
832862
buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) +
833863
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
834-
xdp_page = xdp_linearize_page(rq, &num_buf, page,
864+
xdp_page = xdp_linearize_page(dev, rq, &num_buf, page,
835865
offset, header_offset,
836866
&tlen);
837867
if (!xdp_page)
@@ -1006,7 +1036,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
10061036
if (unlikely(num_buf > 1 ||
10071037
headroom < virtnet_get_headroom(vi))) {
10081038
/* linearize data for XDP */
1009-
xdp_page = xdp_linearize_page(rq, &num_buf,
1039+
xdp_page = xdp_linearize_page(dev, rq, &num_buf,
10101040
page, offset,
10111041
VIRTIO_XDP_HEADROOM,
10121042
&len);

0 commit comments

Comments
 (0)