FAILED: patch "[PATCH] net: check untrusted gso_size at kernel entry" failed to apply to 4.9-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 4.9-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 6dd912f82680761d8fb6b1bb274a69d4c7010988 Mon Sep 17 00:00:00 2001
From: Willem de Bruijn <[email protected]>
Date: Mon, 25 May 2020 15:07:40 -0400
Subject: [PATCH] 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 9274124f023b ("net: stricter validation of untrusted gso packets"), check gso_size at entry too.
include/linux/virtio_net.h +12 -2
@@ -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;