net: check tunnel option type in tunnel flags
authorPieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com>
Wed, 27 Jun 2018 04:39:36 +0000 (21:39 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 29 Jun 2018 14:50:26 +0000 (23:50 +0900)
Check the tunnel option type stored in tunnel flags when creating options
for tunnels. Thereby ensuring we do not set geneve, vxlan or erspan tunnel
options on interfaces that are not associated with them.

Make sure all users of the infrastructure set correct flags, for the BPF
helper we have to set all bits to keep backward compatibility.

Signed-off-by: Pieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com>
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/geneve.c
drivers/net/vxlan.c
include/net/ip_tunnels.h
net/core/filter.c
net/ipv4/ip_gre.c
net/ipv6/ip6_gre.c
net/openvswitch/flow_netlink.c

index 3e94375b9b01cb90494e62bc9883dc84dc76c0f5..471edd76ff55f435bad92b1f63eedeeb5b897998 100644 (file)
@@ -236,7 +236,8 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
                }
                /* Update tunnel dst according to Geneve options. */
                ip_tunnel_info_opts_set(&tun_dst->u.tun_info,
-                                       gnvh->options, gnvh->opt_len * 4);
+                                       gnvh->options, gnvh->opt_len * 4,
+                                       TUNNEL_GENEVE_OPT);
        } else {
                /* Drop packets w/ critical options,
                 * since we don't support any...
@@ -675,7 +676,8 @@ static void geneve_build_header(struct genevehdr *geneveh,
        geneveh->proto_type = htons(ETH_P_TEB);
        geneveh->rsvd2 = 0;
 
-       ip_tunnel_info_opts_get(geneveh->options, info);
+       if (info->key.tun_flags & TUNNEL_GENEVE_OPT)
+               ip_tunnel_info_opts_get(geneveh->options, info);
 }
 
 static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,
index cc14e0cd56470a3e2b92ef3e7b473e567a9272ae..7eb30d7c8bd7b9a6d2b544b27de093c8ffca8673 100644 (file)
@@ -2122,7 +2122,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                vni = tunnel_id_to_key32(info->key.tun_id);
                ifindex = 0;
                dst_cache = &info->dst_cache;
-               if (info->options_len)
+               if (info->options_len &&
+                   info->key.tun_flags & TUNNEL_VXLAN_OPT)
                        md = ip_tunnel_info_opts(info);
                ttl = info->key.ttl;
                tos = info->key.tos;
index 90ff430f5e9d04b1899ccadbc888f6f1376921b4..b0d022ff6ea1702037b84a038f3c81ce56540aa4 100644 (file)
@@ -466,10 +466,12 @@ static inline void ip_tunnel_info_opts_get(void *to,
 }
 
 static inline void ip_tunnel_info_opts_set(struct ip_tunnel_info *info,
-                                          const void *from, int len)
+                                          const void *from, int len,
+                                          __be16 flags)
 {
        memcpy(ip_tunnel_info_opts(info), from, len);
        info->options_len = len;
+       info->key.tun_flags |= flags;
 }
 
 static inline struct ip_tunnel_info *lwt_tun_info(struct lwtunnel_state *lwtstate)
@@ -511,9 +513,11 @@ static inline void ip_tunnel_info_opts_get(void *to,
 }
 
 static inline void ip_tunnel_info_opts_set(struct ip_tunnel_info *info,
-                                          const void *from, int len)
+                                          const void *from, int len,
+                                          __be16 flags)
 {
        info->options_len = 0;
+       info->key.tun_flags |= flags;
 }
 
 #endif /* CONFIG_INET */
index e7f12e9f598c8edfc684e05e3d290a952aa9cf2f..dade922678f6b2506fba693e6061d40e30228fee 100644 (file)
@@ -3582,7 +3582,7 @@ BPF_CALL_3(bpf_skb_set_tunnel_opt, struct sk_buff *, skb,
        if (unlikely(size > IP_TUNNEL_OPTS_MAX))
                return -ENOMEM;
 
-       ip_tunnel_info_opts_set(info, from, size);
+       ip_tunnel_info_opts_set(info, from, size, TUNNEL_OPTIONS_PRESENT);
 
        return 0;
 }
index 2d8efeecf61976f00c0700cc7f64f749b9482a73..c8ca5d8f0f75a911879bfbff4c2c38df77f56f00 100644 (file)
@@ -587,6 +587,8 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev,
                goto err_free_skb;
 
        key = &tun_info->key;
+       if (!(tun_info->key.tun_flags & TUNNEL_ERSPAN_OPT))
+               goto err_free_rt;
        md = ip_tunnel_info_opts(tun_info);
        if (!md)
                goto err_free_rt;
index c8cf2fdbb13b88cc1bf6b494a75407cdc16977eb..367177786e342e64912d75e1c751378179348914 100644 (file)
@@ -990,6 +990,8 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
                fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
 
                dsfield = key->tos;
+               if (!(tun_info->key.tun_flags & TUNNEL_ERSPAN_OPT))
+                       goto tx_err;
                md = ip_tunnel_info_opts(tun_info);
                if (!md)
                        goto tx_err;
index 492ab0c36f7c9e3caf6de7e7d77368028716e09c..391c4073a6dcd7facffca0ccd4e7afe2d0a07d3f 100644 (file)
@@ -2516,7 +2516,9 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
        struct ovs_tunnel_info *ovs_tun;
        struct nlattr *a;
        int err = 0, start, opts_type;
+       __be16 dst_opt_type;
 
+       dst_opt_type = 0;
        ovs_match_init(&match, &key, true, NULL);
        opts_type = ip_tun_from_nlattr(nla_data(attr), &match, false, log);
        if (opts_type < 0)
@@ -2528,10 +2530,13 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
                        err = validate_geneve_opts(&key);
                        if (err < 0)
                                return err;
+                       dst_opt_type = TUNNEL_GENEVE_OPT;
                        break;
                case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS:
+                       dst_opt_type = TUNNEL_VXLAN_OPT;
                        break;
                case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS:
+                       dst_opt_type = TUNNEL_ERSPAN_OPT;
                        break;
                }
        }
@@ -2574,7 +2579,7 @@ static int validate_and_copy_set_tun(const struct nlattr *attr,
         */
        ip_tunnel_info_opts_set(tun_info,
                                TUN_METADATA_OPTS(&key, key.tun_opts_len),
-                               key.tun_opts_len);
+                               key.tun_opts_len, dst_opt_type);
        add_nested_action_end(*sfa, start);
 
        return err;