diff mbox series

[SRU,CVE-2020-25645,Xenial,1/1] geneve: add transport ports in route lookup for geneve

Message ID 20201104180753.41351-2-william.gray@canonical.com
State New
Headers show
Series geneve: add transport ports in route lookup for geneve | expand

Commit Message

William Breathitt Gray Nov. 4, 2020, 6:07 p.m. UTC
From: Mark Gray <mark.d.gray@redhat.com>

This patch adds transport ports information for route lookup so that
IPsec can select Geneve tunnel traffic to do encryption. This is
needed for OVS/OVN IPsec with encrypted Geneve tunnels.

This can be tested by configuring a host-host VPN using an IKE
daemon and specifying port numbers. For example, for an
Openswan-type configuration, the following parameters should be
configured on both hosts and IPsec set up as-per normal:

$ cat /etc/ipsec.conf

conn in
...
left=$IP1
right=$IP2
...
leftprotoport=udp/6081
rightprotoport=udp
...
conn out
...
left=$IP1
right=$IP2
...
leftprotoport=udp
rightprotoport=udp/6081
...

The tunnel can then be setup using "ip" on both hosts (but
changing the relevant IP addresses):

$ ip link add tun type geneve id 1000 remote $IP2
$ ip addr add 192.168.0.1/24 dev tun
$ ip link set tun up

This can then be tested by pinging from $IP1:

$ ping 192.168.0.2

Without this patch the traffic is unencrypted on the wire.

Fixes: 2d07dc79fe04 ("geneve: add initial netdev driver for GENEVE tunnels")
Signed-off-by: Qiuyu Xiao <qiuyu.xiao.qyx@gmail.com>
Signed-off-by: Mark Gray <mark.d.gray@redhat.com>
Reviewed-by: Greg Rose <gvrose8192@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

CVE-2020-25645

(backported from commit 34beb21594519ce64a55a498c2fe7d567bc1ca20)
[ vilhelmgray: context adjustments ]
Signed-off-by: William Breathitt Gray <william.gray@canonical.com>
---
 drivers/net/geneve.c | 32 ++++++++++++++++++++++----------
 1 file changed, 22 insertions(+), 10 deletions(-)

Comments

Thadeu Lima de Souza Cascardo Nov. 5, 2020, 9:55 a.m. UTC | #1
On Wed, Nov 04, 2020 at 01:07:53PM -0500, William Breathitt Gray wrote:
> From: Mark Gray <mark.d.gray@redhat.com>
> 
> This patch adds transport ports information for route lookup so that
> IPsec can select Geneve tunnel traffic to do encryption. This is
> needed for OVS/OVN IPsec with encrypted Geneve tunnels.
> 
> This can be tested by configuring a host-host VPN using an IKE
> daemon and specifying port numbers. For example, for an
> Openswan-type configuration, the following parameters should be
> configured on both hosts and IPsec set up as-per normal:
> 
> $ cat /etc/ipsec.conf
> 
> conn in
> ...
> left=$IP1
> right=$IP2
> ...
> leftprotoport=udp/6081
> rightprotoport=udp
> ...
> conn out
> ...
> left=$IP1
> right=$IP2
> ...
> leftprotoport=udp
> rightprotoport=udp/6081
> ...
> 
> The tunnel can then be setup using "ip" on both hosts (but
> changing the relevant IP addresses):
> 
> $ ip link add tun type geneve id 1000 remote $IP2
> $ ip addr add 192.168.0.1/24 dev tun
> $ ip link set tun up
> 
> This can then be tested by pinging from $IP1:
> 
> $ ping 192.168.0.2
> 
> Without this patch the traffic is unencrypted on the wire.
> 
> Fixes: 2d07dc79fe04 ("geneve: add initial netdev driver for GENEVE tunnels")
> Signed-off-by: Qiuyu Xiao <qiuyu.xiao.qyx@gmail.com>
> Signed-off-by: Mark Gray <mark.d.gray@redhat.com>
> Reviewed-by: Greg Rose <gvrose8192@gmail.com>
> Signed-off-by: David S. Miller <davem@davemloft.net>
> 
> CVE-2020-25645
> 
> (backported from commit 34beb21594519ce64a55a498c2fe7d567bc1ca20)
> [ vilhelmgray: context adjustments ]
> Signed-off-by: William Breathitt Gray <william.gray@canonical.com>
> ---
>  drivers/net/geneve.c | 32 ++++++++++++++++++++++----------
>  1 file changed, 22 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
> index c9e0fa325218..d47dd1be86de 100644
> --- a/drivers/net/geneve.c
> +++ b/drivers/net/geneve.c
> @@ -750,7 +750,8 @@ free_dst:
>  static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
>  				       struct net_device *dev,
>  				       struct flowi4 *fl4,
> -				       struct ip_tunnel_info *info)
> +				       struct ip_tunnel_info *info,
> +				       __be16 dport, __be16 sport)
>  {
>  	struct geneve_dev *geneve = netdev_priv(dev);
>  	struct rtable *rt = NULL;
> @@ -759,6 +760,8 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
>  	memset(fl4, 0, sizeof(*fl4));
>  	fl4->flowi4_mark = skb->mark;
>  	fl4->flowi4_proto = IPPROTO_UDP;
> +	fl4->fl4_dport = dport;
> +	fl4->fl4_sport = sport;
>  
>  	if (info) {
>  		fl4->daddr = info->key.u.ipv4.dst;
> @@ -793,7 +796,8 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
>  static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
>  					   struct net_device *dev,
>  					   struct flowi6 *fl6,
> -					   struct ip_tunnel_info *info)
> +					   struct ip_tunnel_info *info,
> +					   __be16 dport, __be16 sport)
>  {
>  	struct geneve_dev *geneve = netdev_priv(dev);
>  	struct geneve_sock *gs6 = geneve->sock6;
> @@ -803,6 +807,8 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
>  	memset(fl6, 0, sizeof(*fl6));
>  	fl6->flowi6_mark = skb->mark;
>  	fl6->flowi6_proto = IPPROTO_UDP;
> +	fl6->fl6_dport = dport;
> +	fl6->fl6_sport = sport;
>  
>  	if (info) {
>  		fl6->daddr = info->key.u.ipv6.dst;
> @@ -873,13 +879,13 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
>  			goto tx_error;
>  	}
>  
> -	rt = geneve_get_v4_rt(skb, dev, &fl4, info);
> +	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
> +	rt = geneve_get_v4_rt(skb, dev, &fl4, info, geneve->dst_port, sport);
>  	if (IS_ERR(rt)) {
>  		err = PTR_ERR(rt);
>  		goto tx_error;
>  	}
>  
> -	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
>  	skb_reset_mac_header(skb);
>  
>  	if (info) {
> @@ -958,13 +964,13 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
>  		}
>  	}
>  
> -	dst = geneve_get_v6_dst(skb, dev, &fl6, info);
> +	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
> +	dst = geneve_get_v6_dst(skb, dev, &fl6, info, geneve->dst_port, sport);
>  	if (IS_ERR(dst)) {
>  		err = PTR_ERR(dst);
>  		goto tx_error;
>  	}
>  
> -	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
>  	skb_reset_mac_header(skb);
>  
>  	if (info) {
> @@ -1053,6 +1059,7 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
>  {
>  	struct ip_tunnel_info *info = skb_tunnel_info(skb);
>  	struct geneve_dev *geneve = netdev_priv(dev);
> +	__be16 sport;
>  	struct rtable *rt;
>  	struct flowi4 fl4;
>  #if IS_ENABLED(CONFIG_IPV6)
> @@ -1061,7 +1068,10 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
>  #endif
>  
>  	if (ip_tunnel_info_af(info) == AF_INET) {
> -		rt = geneve_get_v4_rt(skb, dev, &fl4, info);
> +		sport = udp_flow_src_port(geneve->net, skb,
> +					  1, USHRT_MAX, true);
> +		rt = geneve_get_v4_rt(skb, dev, &fl4, info, geneve->dst_port,
> +				      sport);
>  		if (IS_ERR(rt))
>  			return PTR_ERR(rt);
>  
> @@ -1069,7 +1079,10 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
>  		info->key.u.ipv4.src = fl4.saddr;
>  #if IS_ENABLED(CONFIG_IPV6)
>  	} else if (ip_tunnel_info_af(info) == AF_INET6) {
> -		dst = geneve_get_v6_dst(skb, dev, &fl6, info);
> +		sport = udp_flow_src_port(geneve->net, skb,
> +					  1, USHRT_MAX, true);
> +		dst = geneve_get_v6_dst(skb, dev, &fl6, info, geneve->dst_port,
> +					sport);
>  		if (IS_ERR(dst))
>  			return PTR_ERR(dst);
>  
> @@ -1080,8 +1093,7 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
>  		return -EINVAL;
>  	}
>  
> -	info->key.tp_src = udp_flow_src_port(geneve->net, skb,
> -					     1, USHRT_MAX, true);
> +	info->key.tp_src = sport;
>  	info->key.tp_dst = geneve->dst_port;
>  	return 0;
>  }
> -- 
> 2.25.1
> 

Acked-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
Ian May Nov. 6, 2020, 12:11 a.m. UTC | #2
Applied to Xenial/master-next

Thanks
Ian

On 2020-11-04 13:07:53 , William Breathitt Gray wrote:
> From: Mark Gray <mark.d.gray@redhat.com>
> 
> This patch adds transport ports information for route lookup so that
> IPsec can select Geneve tunnel traffic to do encryption. This is
> needed for OVS/OVN IPsec with encrypted Geneve tunnels.
> 
> This can be tested by configuring a host-host VPN using an IKE
> daemon and specifying port numbers. For example, for an
> Openswan-type configuration, the following parameters should be
> configured on both hosts and IPsec set up as-per normal:
> 
> $ cat /etc/ipsec.conf
> 
> conn in
> ...
> left=$IP1
> right=$IP2
> ...
> leftprotoport=udp/6081
> rightprotoport=udp
> ...
> conn out
> ...
> left=$IP1
> right=$IP2
> ...
> leftprotoport=udp
> rightprotoport=udp/6081
> ...
> 
> The tunnel can then be setup using "ip" on both hosts (but
> changing the relevant IP addresses):
> 
> $ ip link add tun type geneve id 1000 remote $IP2
> $ ip addr add 192.168.0.1/24 dev tun
> $ ip link set tun up
> 
> This can then be tested by pinging from $IP1:
> 
> $ ping 192.168.0.2
> 
> Without this patch the traffic is unencrypted on the wire.
> 
> Fixes: 2d07dc79fe04 ("geneve: add initial netdev driver for GENEVE tunnels")
> Signed-off-by: Qiuyu Xiao <qiuyu.xiao.qyx@gmail.com>
> Signed-off-by: Mark Gray <mark.d.gray@redhat.com>
> Reviewed-by: Greg Rose <gvrose8192@gmail.com>
> Signed-off-by: David S. Miller <davem@davemloft.net>
> 
> CVE-2020-25645
> 
> (backported from commit 34beb21594519ce64a55a498c2fe7d567bc1ca20)
> [ vilhelmgray: context adjustments ]
> Signed-off-by: William Breathitt Gray <william.gray@canonical.com>
> ---
>  drivers/net/geneve.c | 32 ++++++++++++++++++++++----------
>  1 file changed, 22 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
> index c9e0fa325218..d47dd1be86de 100644
> --- a/drivers/net/geneve.c
> +++ b/drivers/net/geneve.c
> @@ -750,7 +750,8 @@ free_dst:
>  static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
>  				       struct net_device *dev,
>  				       struct flowi4 *fl4,
> -				       struct ip_tunnel_info *info)
> +				       struct ip_tunnel_info *info,
> +				       __be16 dport, __be16 sport)
>  {
>  	struct geneve_dev *geneve = netdev_priv(dev);
>  	struct rtable *rt = NULL;
> @@ -759,6 +760,8 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
>  	memset(fl4, 0, sizeof(*fl4));
>  	fl4->flowi4_mark = skb->mark;
>  	fl4->flowi4_proto = IPPROTO_UDP;
> +	fl4->fl4_dport = dport;
> +	fl4->fl4_sport = sport;
>  
>  	if (info) {
>  		fl4->daddr = info->key.u.ipv4.dst;
> @@ -793,7 +796,8 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
>  static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
>  					   struct net_device *dev,
>  					   struct flowi6 *fl6,
> -					   struct ip_tunnel_info *info)
> +					   struct ip_tunnel_info *info,
> +					   __be16 dport, __be16 sport)
>  {
>  	struct geneve_dev *geneve = netdev_priv(dev);
>  	struct geneve_sock *gs6 = geneve->sock6;
> @@ -803,6 +807,8 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
>  	memset(fl6, 0, sizeof(*fl6));
>  	fl6->flowi6_mark = skb->mark;
>  	fl6->flowi6_proto = IPPROTO_UDP;
> +	fl6->fl6_dport = dport;
> +	fl6->fl6_sport = sport;
>  
>  	if (info) {
>  		fl6->daddr = info->key.u.ipv6.dst;
> @@ -873,13 +879,13 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
>  			goto tx_error;
>  	}
>  
> -	rt = geneve_get_v4_rt(skb, dev, &fl4, info);
> +	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
> +	rt = geneve_get_v4_rt(skb, dev, &fl4, info, geneve->dst_port, sport);
>  	if (IS_ERR(rt)) {
>  		err = PTR_ERR(rt);
>  		goto tx_error;
>  	}
>  
> -	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
>  	skb_reset_mac_header(skb);
>  
>  	if (info) {
> @@ -958,13 +964,13 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
>  		}
>  	}
>  
> -	dst = geneve_get_v6_dst(skb, dev, &fl6, info);
> +	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
> +	dst = geneve_get_v6_dst(skb, dev, &fl6, info, geneve->dst_port, sport);
>  	if (IS_ERR(dst)) {
>  		err = PTR_ERR(dst);
>  		goto tx_error;
>  	}
>  
> -	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
>  	skb_reset_mac_header(skb);
>  
>  	if (info) {
> @@ -1053,6 +1059,7 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
>  {
>  	struct ip_tunnel_info *info = skb_tunnel_info(skb);
>  	struct geneve_dev *geneve = netdev_priv(dev);
> +	__be16 sport;
>  	struct rtable *rt;
>  	struct flowi4 fl4;
>  #if IS_ENABLED(CONFIG_IPV6)
> @@ -1061,7 +1068,10 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
>  #endif
>  
>  	if (ip_tunnel_info_af(info) == AF_INET) {
> -		rt = geneve_get_v4_rt(skb, dev, &fl4, info);
> +		sport = udp_flow_src_port(geneve->net, skb,
> +					  1, USHRT_MAX, true);
> +		rt = geneve_get_v4_rt(skb, dev, &fl4, info, geneve->dst_port,
> +				      sport);
>  		if (IS_ERR(rt))
>  			return PTR_ERR(rt);
>  
> @@ -1069,7 +1079,10 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
>  		info->key.u.ipv4.src = fl4.saddr;
>  #if IS_ENABLED(CONFIG_IPV6)
>  	} else if (ip_tunnel_info_af(info) == AF_INET6) {
> -		dst = geneve_get_v6_dst(skb, dev, &fl6, info);
> +		sport = udp_flow_src_port(geneve->net, skb,
> +					  1, USHRT_MAX, true);
> +		dst = geneve_get_v6_dst(skb, dev, &fl6, info, geneve->dst_port,
> +					sport);
>  		if (IS_ERR(dst))
>  			return PTR_ERR(dst);
>  
> @@ -1080,8 +1093,7 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
>  		return -EINVAL;
>  	}
>  
> -	info->key.tp_src = udp_flow_src_port(geneve->net, skb,
> -					     1, USHRT_MAX, true);
> +	info->key.tp_src = sport;
>  	info->key.tp_dst = geneve->dst_port;
>  	return 0;
>  }
> -- 
> 2.25.1
> 
> 
> -- 
> kernel-team mailing list
> kernel-team@lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/kernel-team
diff mbox series

Patch

diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index c9e0fa325218..d47dd1be86de 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -750,7 +750,8 @@  free_dst:
 static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
 				       struct net_device *dev,
 				       struct flowi4 *fl4,
-				       struct ip_tunnel_info *info)
+				       struct ip_tunnel_info *info,
+				       __be16 dport, __be16 sport)
 {
 	struct geneve_dev *geneve = netdev_priv(dev);
 	struct rtable *rt = NULL;
@@ -759,6 +760,8 @@  static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
 	memset(fl4, 0, sizeof(*fl4));
 	fl4->flowi4_mark = skb->mark;
 	fl4->flowi4_proto = IPPROTO_UDP;
+	fl4->fl4_dport = dport;
+	fl4->fl4_sport = sport;
 
 	if (info) {
 		fl4->daddr = info->key.u.ipv4.dst;
@@ -793,7 +796,8 @@  static struct rtable *geneve_get_v4_rt(struct sk_buff *skb,
 static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
 					   struct net_device *dev,
 					   struct flowi6 *fl6,
-					   struct ip_tunnel_info *info)
+					   struct ip_tunnel_info *info,
+					   __be16 dport, __be16 sport)
 {
 	struct geneve_dev *geneve = netdev_priv(dev);
 	struct geneve_sock *gs6 = geneve->sock6;
@@ -803,6 +807,8 @@  static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb,
 	memset(fl6, 0, sizeof(*fl6));
 	fl6->flowi6_mark = skb->mark;
 	fl6->flowi6_proto = IPPROTO_UDP;
+	fl6->fl6_dport = dport;
+	fl6->fl6_sport = sport;
 
 	if (info) {
 		fl6->daddr = info->key.u.ipv6.dst;
@@ -873,13 +879,13 @@  static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 			goto tx_error;
 	}
 
-	rt = geneve_get_v4_rt(skb, dev, &fl4, info);
+	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
+	rt = geneve_get_v4_rt(skb, dev, &fl4, info, geneve->dst_port, sport);
 	if (IS_ERR(rt)) {
 		err = PTR_ERR(rt);
 		goto tx_error;
 	}
 
-	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
 	skb_reset_mac_header(skb);
 
 	if (info) {
@@ -958,13 +964,13 @@  static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 		}
 	}
 
-	dst = geneve_get_v6_dst(skb, dev, &fl6, info);
+	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
+	dst = geneve_get_v6_dst(skb, dev, &fl6, info, geneve->dst_port, sport);
 	if (IS_ERR(dst)) {
 		err = PTR_ERR(dst);
 		goto tx_error;
 	}
 
-	sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true);
 	skb_reset_mac_header(skb);
 
 	if (info) {
@@ -1053,6 +1059,7 @@  static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 {
 	struct ip_tunnel_info *info = skb_tunnel_info(skb);
 	struct geneve_dev *geneve = netdev_priv(dev);
+	__be16 sport;
 	struct rtable *rt;
 	struct flowi4 fl4;
 #if IS_ENABLED(CONFIG_IPV6)
@@ -1061,7 +1068,10 @@  static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 #endif
 
 	if (ip_tunnel_info_af(info) == AF_INET) {
-		rt = geneve_get_v4_rt(skb, dev, &fl4, info);
+		sport = udp_flow_src_port(geneve->net, skb,
+					  1, USHRT_MAX, true);
+		rt = geneve_get_v4_rt(skb, dev, &fl4, info, geneve->dst_port,
+				      sport);
 		if (IS_ERR(rt))
 			return PTR_ERR(rt);
 
@@ -1069,7 +1079,10 @@  static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 		info->key.u.ipv4.src = fl4.saddr;
 #if IS_ENABLED(CONFIG_IPV6)
 	} else if (ip_tunnel_info_af(info) == AF_INET6) {
-		dst = geneve_get_v6_dst(skb, dev, &fl6, info);
+		sport = udp_flow_src_port(geneve->net, skb,
+					  1, USHRT_MAX, true);
+		dst = geneve_get_v6_dst(skb, dev, &fl6, info, geneve->dst_port,
+					sport);
 		if (IS_ERR(dst))
 			return PTR_ERR(dst);
 
@@ -1080,8 +1093,7 @@  static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 		return -EINVAL;
 	}
 
-	info->key.tp_src = udp_flow_src_port(geneve->net, skb,
-					     1, USHRT_MAX, true);
+	info->key.tp_src = sport;
 	info->key.tp_dst = geneve->dst_port;
 	return 0;
 }