net: avoid false positives in untrusted gso validation [Linux 5.0]

net: avoid false positives in untrusted gso validation [Linux 5.0]

This Linux kernel change "net: avoid false positives in untrusted gso validation" is included in the Linux 5.0 release. This change is authored by Willem de Bruijn <willemb [at] google.com> on Mon Feb 18 23:37:12 2019 -0500. The commit for this change in Linux stable tree is 9e8db59 (patch).

net: avoid false positives in untrusted gso validation

GSO packets with vnet_hdr must conform to a small set of gso_types.
The below commit uses flow dissection to drop packets that do not.

But it has false positives when the skb is not fully initialized.
Dissection needs skb->protocol and skb->network_header.

Infer skb->protocol from gso_type as the two must agree.
SKB_GSO_UDP can use both ipv4 and ipv6, so try both.

Exclude callers for which network header offset is not known.

Fixes: d5be7f632bad ("net: validate untrusted gso packets without csum offload")
Signed-off-by: Willem de Bruijn <[email protected]>
Signed-off-by: David S. Miller <[email protected]>

There are 14 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 include/linux/virtio_net.h | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index 71f2394..e0348cb 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -61,10 +61,20 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
        /* 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) {
+       if (gso_type && skb->network_header) {
+           if (!skb->protocol)
+               virtio_net_hdr_set_proto(skb, hdr);
+retry:
            skb_probe_transport_header(skb, -1);
-           if (!skb_transport_header_was_set(skb))
+           if (!skb_transport_header_was_set(skb)) {
+               /* UFO does not specify ipv4 or 6: try both */
+               if (gso_type & SKB_GSO_UDP &&
+                   skb->protocol == htons(ETH_P_IP)) {
+                   skb->protocol = htons(ETH_P_IPV6);
+                   goto retry;
+               }
                return -EINVAL;
+           }
        }
    }

Leave a Reply

Your email address will not be published. Required fields are marked *