aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWANG Cong <xiyou.wangcong@gmail.com>2017-04-25 17:37:15 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-03 11:36:37 -0400
commitdf1926123f0c390d4ccbea5760ac0428b6f7cae4 (patch)
tree0b97ae8d2641003b9d60d234fc83b1925a2684bf
parentae6a762dcdf0a72baa448dbd8d5d77ad89ca1962 (diff)
ipv6: check skb->protocol before lookup for nexthop
[ Upstream commit 199ab00f3cdb6f154ea93fa76fd80192861a821d ] Andrey reported a out-of-bound access in ip6_tnl_xmit(), this is because we use an ipv4 dst in ip6_tnl_xmit() and cast an IPv4 neigh key as an IPv6 address: neigh = dst_neigh_lookup(skb_dst(skb), &ipv6_hdr(skb)->daddr); if (!neigh) goto tx_err_link_failure; addr6 = (struct in6_addr *)&neigh->primary_key; // <=== HERE addr_type = ipv6_addr_type(addr6); if (addr_type == IPV6_ADDR_ANY) addr6 = &ipv6_hdr(skb)->daddr; memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr)); Also the network header of the skb at this point should be still IPv4 for 4in6 tunnels, we shold not just use it as IPv6 header. This patch fixes it by checking if skb->protocol is ETH_P_IPV6: if it is, we are safe to do the nexthop lookup using skb_dst() and ipv6_hdr(skb)->daddr; if not (aka IPv4), we have no clue about which dest address we can pick here, we have to rely on callers to fill it from tunnel config, so just fall to ip6_route_output() to make the decision. Fixes: ea3dc9601bda ("ip6_tunnel: Add support for wildcard tunnel endpoints.") Reported-by: Andrey Konovalov <andreyknvl@google.com> Tested-by: Andrey Konovalov <andreyknvl@google.com> Cc: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--net/ipv6/ip6_tunnel.c34
1 files changed, 18 insertions, 16 deletions
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index f6ba45242851..116b4da06820 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1037,7 +1037,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
1037 struct ip6_tnl *t = netdev_priv(dev); 1037 struct ip6_tnl *t = netdev_priv(dev);
1038 struct net *net = t->net; 1038 struct net *net = t->net;
1039 struct net_device_stats *stats = &t->dev->stats; 1039 struct net_device_stats *stats = &t->dev->stats;
1040 struct ipv6hdr *ipv6h = ipv6_hdr(skb); 1040 struct ipv6hdr *ipv6h;
1041 struct ipv6_tel_txoption opt; 1041 struct ipv6_tel_txoption opt;
1042 struct dst_entry *dst = NULL, *ndst = NULL; 1042 struct dst_entry *dst = NULL, *ndst = NULL;
1043 struct net_device *tdev; 1043 struct net_device *tdev;
@@ -1057,26 +1057,28 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
1057 1057
1058 /* NBMA tunnel */ 1058 /* NBMA tunnel */
1059 if (ipv6_addr_any(&t->parms.raddr)) { 1059 if (ipv6_addr_any(&t->parms.raddr)) {
1060 struct in6_addr *addr6; 1060 if (skb->protocol == htons(ETH_P_IPV6)) {
1061 struct neighbour *neigh; 1061 struct in6_addr *addr6;
1062 int addr_type; 1062 struct neighbour *neigh;
1063 int addr_type;
1063 1064
1064 if (!skb_dst(skb)) 1065 if (!skb_dst(skb))
1065 goto tx_err_link_failure; 1066 goto tx_err_link_failure;
1066 1067
1067 neigh = dst_neigh_lookup(skb_dst(skb), 1068 neigh = dst_neigh_lookup(skb_dst(skb),
1068 &ipv6_hdr(skb)->daddr); 1069 &ipv6_hdr(skb)->daddr);
1069 if (!neigh) 1070 if (!neigh)
1070 goto tx_err_link_failure; 1071 goto tx_err_link_failure;
1071 1072
1072 addr6 = (struct in6_addr *)&neigh->primary_key; 1073 addr6 = (struct in6_addr *)&neigh->primary_key;
1073 addr_type = ipv6_addr_type(addr6); 1074 addr_type = ipv6_addr_type(addr6);
1074 1075
1075 if (addr_type == IPV6_ADDR_ANY) 1076 if (addr_type == IPV6_ADDR_ANY)
1076 addr6 = &ipv6_hdr(skb)->daddr; 1077 addr6 = &ipv6_hdr(skb)->daddr;
1077 1078
1078 memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr)); 1079 memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
1079 neigh_release(neigh); 1080 neigh_release(neigh);
1081 }
1080 } else if (!(t->parms.flags & 1082 } else if (!(t->parms.flags &
1081 (IP6_TNL_F_USE_ORIG_TCLASS | IP6_TNL_F_USE_ORIG_FWMARK))) { 1083 (IP6_TNL_F_USE_ORIG_TCLASS | IP6_TNL_F_USE_ORIG_FWMARK))) {
1082 /* enable the cache only only if the routing decision does 1084 /* enable the cache only only if the routing decision does