Skip to content

Commit 0c71670

Browse files
minhbq-99kuba-moo
authored andcommitted
virtio-net: fix received length check in big packets
Since commit 4959aeb ("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: 4959aeb ("virtio-net: use mtu size as buffer length for big packets") Cc: [email protected] Signed-off-by: Bui Quang Minh <[email protected]> Reviewed-by: Xuan Zhuo <[email protected]> Tested-by: Lei Yang <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent a30297d commit 0c71670

File tree

1 file changed

+12
-13
lines changed

1 file changed

+12
-13
lines changed

drivers/net/virtio_net.c

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -910,17 +910,6 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi,
910910
goto ok;
911911
}
912912

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-
}
924913
BUG_ON(offset >= PAGE_SIZE);
925914
while (len) {
926915
unsigned int frag_size = min((unsigned)PAGE_SIZE - offset, len);
@@ -2112,9 +2101,19 @@ static struct sk_buff *receive_big(struct net_device *dev,
21122101
struct virtnet_rq_stats *stats)
21132102
{
21142103
struct page *page = buf;
2115-
struct sk_buff *skb =
2116-
page_to_skb(vi, rq, page, 0, len, PAGE_SIZE, 0);
2104+
struct sk_buff *skb;
2105+
2106+
/* Make sure that len does not exceed the size allocated in
2107+
* add_recvbuf_big.
2108+
*/
2109+
if (unlikely(len > (vi->big_packets_num_skbfrags + 1) * PAGE_SIZE)) {
2110+
pr_debug("%s: rx error: len %u exceeds allocated size %lu\n",
2111+
dev->name, len,
2112+
(vi->big_packets_num_skbfrags + 1) * PAGE_SIZE);
2113+
goto err;
2114+
}
21172115

2116+
skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE, 0);
21182117
u64_stats_add(&stats->bytes, len - vi->hdr_len);
21192118
if (unlikely(!skb))
21202119
goto err;

0 commit comments

Comments
 (0)