Skip to content

Commit 6dd912f

Browse files
wdebruijdavem330
authored andcommitted
net: check untrusted gso_size at kernel entry
Syzkaller again found a path to a kernel crash through bad gso input: a packet with gso size exceeding len. These packets are dropped in tcp_gso_segment and udp[46]_ufo_fragment. But they may affect gso size calculations earlier in the path. Now that we have thlen as of commit 9274124 ("net: stricter validation of untrusted gso packets"), check gso_size at entry too. Fixes: bfd5f4a ("packet: Add GSO/csum offload support.") Reported-by: syzbot <syzkaller@googlegroups.com> Signed-off-by: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 0a82e23 commit 6dd912f

File tree

1 file changed

+12
-2
lines changed

1 file changed

+12
-2
lines changed

include/linux/virtio_net.h

+12-2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
3131
{
3232
unsigned int gso_type = 0;
3333
unsigned int thlen = 0;
34+
unsigned int p_off = 0;
3435
unsigned int ip_proto;
3536

3637
if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
@@ -68,7 +69,8 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
6869
if (!skb_partial_csum_set(skb, start, off))
6970
return -EINVAL;
7071

71-
if (skb_transport_offset(skb) + thlen > skb_headlen(skb))
72+
p_off = skb_transport_offset(skb) + thlen;
73+
if (p_off > skb_headlen(skb))
7274
return -EINVAL;
7375
} else {
7476
/* gso packets without NEEDS_CSUM do not set transport_offset.
@@ -92,17 +94,25 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
9294
return -EINVAL;
9395
}
9496

95-
if (keys.control.thoff + thlen > skb_headlen(skb) ||
97+
p_off = keys.control.thoff + thlen;
98+
if (p_off > skb_headlen(skb) ||
9699
keys.basic.ip_proto != ip_proto)
97100
return -EINVAL;
98101

99102
skb_set_transport_header(skb, keys.control.thoff);
103+
} else if (gso_type) {
104+
p_off = thlen;
105+
if (p_off > skb_headlen(skb))
106+
return -EINVAL;
100107
}
101108
}
102109

103110
if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
104111
u16 gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size);
105112

113+
if (skb->len - p_off <= gso_size)
114+
return -EINVAL;
115+
106116
skb_shinfo(skb)->gso_size = gso_size;
107117
skb_shinfo(skb)->gso_type = gso_type;
108118

0 commit comments

Comments
 (0)