Skip to content

Commit befb925

Browse files
congwanggregkh
authored andcommitted
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: ea3dc96 ("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>
1 parent 114f0c6 commit befb925

1 file changed

Lines changed: 18 additions & 16 deletions

File tree

net/ipv6/ip6_tunnel.c

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,7 +1049,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
10491049
struct ip6_tnl *t = netdev_priv(dev);
10501050
struct net *net = t->net;
10511051
struct net_device_stats *stats = &t->dev->stats;
1052-
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
1052+
struct ipv6hdr *ipv6h;
10531053
struct ipv6_tel_txoption opt;
10541054
struct dst_entry *dst = NULL, *ndst = NULL;
10551055
struct net_device *tdev;
@@ -1061,26 +1061,28 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
10611061

10621062
/* NBMA tunnel */
10631063
if (ipv6_addr_any(&t->parms.raddr)) {
1064-
struct in6_addr *addr6;
1065-
struct neighbour *neigh;
1066-
int addr_type;
1064+
if (skb->protocol == htons(ETH_P_IPV6)) {
1065+
struct in6_addr *addr6;
1066+
struct neighbour *neigh;
1067+
int addr_type;
10671068

1068-
if (!skb_dst(skb))
1069-
goto tx_err_link_failure;
1069+
if (!skb_dst(skb))
1070+
goto tx_err_link_failure;
10701071

1071-
neigh = dst_neigh_lookup(skb_dst(skb),
1072-
&ipv6_hdr(skb)->daddr);
1073-
if (!neigh)
1074-
goto tx_err_link_failure;
1072+
neigh = dst_neigh_lookup(skb_dst(skb),
1073+
&ipv6_hdr(skb)->daddr);
1074+
if (!neigh)
1075+
goto tx_err_link_failure;
10751076

1076-
addr6 = (struct in6_addr *)&neigh->primary_key;
1077-
addr_type = ipv6_addr_type(addr6);
1077+
addr6 = (struct in6_addr *)&neigh->primary_key;
1078+
addr_type = ipv6_addr_type(addr6);
10781079

1079-
if (addr_type == IPV6_ADDR_ANY)
1080-
addr6 = &ipv6_hdr(skb)->daddr;
1080+
if (addr_type == IPV6_ADDR_ANY)
1081+
addr6 = &ipv6_hdr(skb)->daddr;
10811082

1082-
memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
1083-
neigh_release(neigh);
1083+
memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
1084+
neigh_release(neigh);
1085+
}
10841086
} else if (!(t->parms.flags &
10851087
(IP6_TNL_F_USE_ORIG_TCLASS | IP6_TNL_F_USE_ORIG_FWMARK))) {
10861088
/* enable the cache only only if the routing decision does

0 commit comments

Comments
 (0)