forked from mirrors/linux
		
	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 commit9274124f02("net: stricter validation of untrusted gso packets"), check gso_size at entry too. Fixes:bfd5f4a3d6("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>
This commit is contained in:
		
							parent
							
								
									0a82e230c6
								
							
						
					
					
						commit
						6dd912f826
					
				
					 1 changed files with 12 additions and 2 deletions
				
			
		| 
						 | 
				
			
			@ -31,6 +31,7 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
 | 
			
		|||
{
 | 
			
		||||
	unsigned int gso_type = 0;
 | 
			
		||||
	unsigned int thlen = 0;
 | 
			
		||||
	unsigned int p_off = 0;
 | 
			
		||||
	unsigned int ip_proto;
 | 
			
		||||
 | 
			
		||||
	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,
 | 
			
		|||
		if (!skb_partial_csum_set(skb, start, off))
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
 | 
			
		||||
		if (skb_transport_offset(skb) + thlen > skb_headlen(skb))
 | 
			
		||||
		p_off = skb_transport_offset(skb) + thlen;
 | 
			
		||||
		if (p_off > skb_headlen(skb))
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
	} else {
 | 
			
		||||
		/* 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,
 | 
			
		|||
				return -EINVAL;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (keys.control.thoff + thlen > skb_headlen(skb) ||
 | 
			
		||||
			p_off = keys.control.thoff + thlen;
 | 
			
		||||
			if (p_off > skb_headlen(skb) ||
 | 
			
		||||
			    keys.basic.ip_proto != ip_proto)
 | 
			
		||||
				return -EINVAL;
 | 
			
		||||
 | 
			
		||||
			skb_set_transport_header(skb, keys.control.thoff);
 | 
			
		||||
		} else if (gso_type) {
 | 
			
		||||
			p_off = thlen;
 | 
			
		||||
			if (p_off > skb_headlen(skb))
 | 
			
		||||
				return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
 | 
			
		||||
		u16 gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size);
 | 
			
		||||
 | 
			
		||||
		if (skb->len - p_off <= gso_size)
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
 | 
			
		||||
		skb_shinfo(skb)->gso_size = gso_size;
 | 
			
		||||
		skb_shinfo(skb)->gso_type = gso_type;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue