Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

virtio-net: fix received length check in big packets

Since commit 4959aebba8c0 ("virtio-net: use mtu size as buffer length
for big packets"), when guest gso is off, the allocated size for big
packets is not MAX_SKB_FRAGS * PAGE_SIZE anymore but depends on
negotiated MTU. The number of allocated frags for big packets is stored
in vi->big_packets_num_skbfrags.

Because the host announced buffer length can be malicious (e.g. the host
vhost_net driver's get_rx_bufs is modified to announce incorrect
length), we need a check in virtio_net receive path. Currently, the
check is not adapted to the new change which can lead to NULL page
pointer dereference in the below while loop when receiving length that
is larger than the allocated one.

This commit fixes the received length check corresponding to the new
change.

Fixes: 4959aebba8c0 ("virtio-net: use mtu size as buffer length for big packets")
Cc: stable@vger.kernel.org
Signed-off-by: Bui Quang Minh <minhquangbui99@gmail.com>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Tested-by: Lei Yang <leiyang@redhat.com>
Link: https://patch.msgid.link/20251030144438.7582-1-minhquangbui99@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Bui Quang Minh and committed by
Jakub Kicinski
0c716703 a30297d3

+12 -13
+12 -13
drivers/net/virtio_net.c
··· 910 910 goto ok; 911 911 } 912 912 913 - /* 914 - * Verify that we can indeed put this data into a skb. 915 - * This is here to handle cases when the device erroneously 916 - * tries to receive more than is possible. This is usually 917 - * the case of a broken device. 918 - */ 919 - if (unlikely(len > MAX_SKB_FRAGS * PAGE_SIZE)) { 920 - net_dbg_ratelimited("%s: too much data\n", skb->dev->name); 921 - dev_kfree_skb(skb); 922 - return NULL; 923 - } 924 913 BUG_ON(offset >= PAGE_SIZE); 925 914 while (len) { 926 915 unsigned int frag_size = min((unsigned)PAGE_SIZE - offset, len); ··· 2101 2112 struct virtnet_rq_stats *stats) 2102 2113 { 2103 2114 struct page *page = buf; 2104 - struct sk_buff *skb = 2105 - page_to_skb(vi, rq, page, 0, len, PAGE_SIZE, 0); 2115 + struct sk_buff *skb; 2106 2116 2117 + /* Make sure that len does not exceed the size allocated in 2118 + * add_recvbuf_big. 2119 + */ 2120 + if (unlikely(len > (vi->big_packets_num_skbfrags + 1) * PAGE_SIZE)) { 2121 + pr_debug("%s: rx error: len %u exceeds allocated size %lu\n", 2122 + dev->name, len, 2123 + (vi->big_packets_num_skbfrags + 1) * PAGE_SIZE); 2124 + goto err; 2125 + } 2126 + 2127 + skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE, 0); 2107 2128 u64_stats_add(&stats->bytes, len - vi->hdr_len); 2108 2129 if (unlikely(!skb)) 2109 2130 goto err;