gso: validate gso_type on ipip style tunnels
authorWillem de Bruijn <willemb@google.com>
Wed, 20 Feb 2019 15:52:12 +0000 (10:52 -0500)
committerDavid S. Miller <davem@davemloft.net>
Wed, 20 Feb 2019 19:24:27 +0000 (11:24 -0800)
Commit 121d57af308d ("gso: validate gso_type in GSO handlers") added
gso_type validation to existing gso_segment callback functions, to
filter out illegal and potentially dangerous SKB_GSO_DODGY packets.

Convert tunnels that now call inet_gso_segment and ipv6_gso_segment
directly to have their own callbacks and extend validation to these.

Signed-off-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/af_inet.c
net/ipv6/ip6_offload.c

index 0dfb72c..eab3ebd 100644 (file)
@@ -1385,6 +1385,15 @@ out:
 }
 EXPORT_SYMBOL(inet_gso_segment);
 
+static struct sk_buff *ipip_gso_segment(struct sk_buff *skb,
+                                       netdev_features_t features)
+{
+       if (!(skb_shinfo(skb)->gso_type & SKB_GSO_IPXIP4))
+               return ERR_PTR(-EINVAL);
+
+       return inet_gso_segment(skb, features);
+}
+
 INDIRECT_CALLABLE_DECLARE(struct sk_buff *tcp4_gro_receive(struct list_head *,
                                                           struct sk_buff *));
 INDIRECT_CALLABLE_DECLARE(struct sk_buff *udp4_gro_receive(struct list_head *,
@@ -1861,7 +1870,7 @@ static struct packet_offload ip_packet_offload __read_mostly = {
 
 static const struct net_offload ipip_offload = {
        .callbacks = {
-               .gso_segment    = inet_gso_segment,
+               .gso_segment    = ipip_gso_segment,
                .gro_receive    = ipip_gro_receive,
                .gro_complete   = ipip_gro_complete,
        },
index 5c04569..345882d 100644 (file)
@@ -383,9 +383,36 @@ static struct packet_offload ipv6_packet_offload __read_mostly = {
        },
 };
 
+static struct sk_buff *sit_gso_segment(struct sk_buff *skb,
+                                      netdev_features_t features)
+{
+       if (!(skb_shinfo(skb)->gso_type & SKB_GSO_IPXIP4))
+               return ERR_PTR(-EINVAL);
+
+       return ipv6_gso_segment(skb, features);
+}
+
+static struct sk_buff *ip4ip6_gso_segment(struct sk_buff *skb,
+                                         netdev_features_t features)
+{
+       if (!(skb_shinfo(skb)->gso_type & SKB_GSO_IPXIP6))
+               return ERR_PTR(-EINVAL);
+
+       return inet_gso_segment(skb, features);
+}
+
+static struct sk_buff *ip6ip6_gso_segment(struct sk_buff *skb,
+                                         netdev_features_t features)
+{
+       if (!(skb_shinfo(skb)->gso_type & SKB_GSO_IPXIP6))
+               return ERR_PTR(-EINVAL);
+
+       return ipv6_gso_segment(skb, features);
+}
+
 static const struct net_offload sit_offload = {
        .callbacks = {
-               .gso_segment    = ipv6_gso_segment,
+               .gso_segment    = sit_gso_segment,
                .gro_receive    = sit_ip6ip6_gro_receive,
                .gro_complete   = sit_gro_complete,
        },
@@ -393,7 +420,7 @@ static const struct net_offload sit_offload = {
 
 static const struct net_offload ip4ip6_offload = {
        .callbacks = {
-               .gso_segment    = inet_gso_segment,
+               .gso_segment    = ip4ip6_gso_segment,
                .gro_receive    = ip4ip6_gro_receive,
                .gro_complete   = ip4ip6_gro_complete,
        },
@@ -401,7 +428,7 @@ static const struct net_offload ip4ip6_offload = {
 
 static const struct net_offload ip6ip6_offload = {
        .callbacks = {
-               .gso_segment    = ipv6_gso_segment,
+               .gso_segment    = ip6ip6_gso_segment,
                .gro_receive    = sit_ip6ip6_gro_receive,
                .gro_complete   = ip6ip6_gro_complete,
        },