diff options
Diffstat (limited to 'include/linux/virtio_net.h')
| -rw-r--r-- | include/linux/virtio_net.h | 26 | 
1 files changed, 24 insertions, 2 deletions
| diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h index 0d1fe9297ac6..6f6ade63b04c 100644 --- a/include/linux/virtio_net.h +++ b/include/linux/virtio_net.h @@ -3,6 +3,8 @@  #define _LINUX_VIRTIO_NET_H  #include <linux/if_vlan.h> +#include <uapi/linux/tcp.h> +#include <uapi/linux/udp.h>  #include <uapi/linux/virtio_net.h>  static inline int virtio_net_hdr_set_proto(struct sk_buff *skb, @@ -28,17 +30,25 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,  					bool little_endian)  {  	unsigned int gso_type = 0; +	unsigned int thlen = 0; +	unsigned int ip_proto;  	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {  		switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {  		case VIRTIO_NET_HDR_GSO_TCPV4:  			gso_type = SKB_GSO_TCPV4; +			ip_proto = IPPROTO_TCP; +			thlen = sizeof(struct tcphdr);  			break;  		case VIRTIO_NET_HDR_GSO_TCPV6:  			gso_type = SKB_GSO_TCPV6; +			ip_proto = IPPROTO_TCP; +			thlen = sizeof(struct tcphdr);  			break;  		case VIRTIO_NET_HDR_GSO_UDP:  			gso_type = SKB_GSO_UDP; +			ip_proto = IPPROTO_UDP; +			thlen = sizeof(struct udphdr);  			break;  		default:  			return -EINVAL; @@ -57,16 +67,22 @@ 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)) +			return -EINVAL;  	} else {  		/* gso packets without NEEDS_CSUM do not set transport_offset.  		 * probe and drop if does not match one of the above types.  		 */  		if (gso_type && skb->network_header) { +			struct flow_keys_basic keys; +  			if (!skb->protocol)  				virtio_net_hdr_set_proto(skb, hdr);  retry: -			skb_probe_transport_header(skb); -			if (!skb_transport_header_was_set(skb)) { +			if (!skb_flow_dissect_flow_keys_basic(NULL, skb, &keys, +							      NULL, 0, 0, 0, +							      0)) {  				/* UFO does not specify ipv4 or 6: try both */  				if (gso_type & SKB_GSO_UDP &&  				    skb->protocol == htons(ETH_P_IP)) { @@ -75,6 +91,12 @@ retry:  				}  				return -EINVAL;  			} + +			if (keys.control.thoff + thlen > skb_headlen(skb) || +			    keys.basic.ip_proto != ip_proto) +				return -EINVAL; + +			skb_set_transport_header(skb, keys.control.thoff);  		}  	} |