Skip to content

Commit 199ab00

Browse files
congwangdavem330
authored andcommitted
ipv6: check skb->protocol before lookup for nexthop
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 <[email protected]> Tested-by: Andrey Konovalov <[email protected]> Cc: Steffen Klassert <[email protected]> Signed-off-by: Cong Wang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 9899886 commit 199ab00

File tree

1 file changed

+18
-16
lines changed

1 file changed

+18
-16
lines changed

net/ipv6/ip6_tunnel.c

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,7 +1037,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
10371037
struct ip6_tnl *t = netdev_priv(dev);
10381038
struct net *net = t->net;
10391039
struct net_device_stats *stats = &t->dev->stats;
1040-
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
1040+
struct ipv6hdr *ipv6h;
10411041
struct ipv6_tel_txoption opt;
10421042
struct dst_entry *dst = NULL, *ndst = NULL;
10431043
struct net_device *tdev;
@@ -1057,26 +1057,28 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
10571057

10581058
/* NBMA tunnel */
10591059
if (ipv6_addr_any(&t->parms.raddr)) {
1060-
struct in6_addr *addr6;
1061-
struct neighbour *neigh;
1062-
int addr_type;
1060+
if (skb->protocol == htons(ETH_P_IPV6)) {
1061+
struct in6_addr *addr6;
1062+
struct neighbour *neigh;
1063+
int addr_type;
10631064

1064-
if (!skb_dst(skb))
1065-
goto tx_err_link_failure;
1065+
if (!skb_dst(skb))
1066+
goto tx_err_link_failure;
10661067

1067-
neigh = dst_neigh_lookup(skb_dst(skb),
1068-
&ipv6_hdr(skb)->daddr);
1069-
if (!neigh)
1070-
goto tx_err_link_failure;
1068+
neigh = dst_neigh_lookup(skb_dst(skb),
1069+
&ipv6_hdr(skb)->daddr);
1070+
if (!neigh)
1071+
goto tx_err_link_failure;
10711072

1072-
addr6 = (struct in6_addr *)&neigh->primary_key;
1073-
addr_type = ipv6_addr_type(addr6);
1073+
addr6 = (struct in6_addr *)&neigh->primary_key;
1074+
addr_type = ipv6_addr_type(addr6);
10741075

1075-
if (addr_type == IPV6_ADDR_ANY)
1076-
addr6 = &ipv6_hdr(skb)->daddr;
1076+
if (addr_type == IPV6_ADDR_ANY)
1077+
addr6 = &ipv6_hdr(skb)->daddr;
10771078

1078-
memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
1079-
neigh_release(neigh);
1079+
memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr));
1080+
neigh_release(neigh);
1081+
}
10801082
} else if (!(t->parms.flags &
10811083
(IP6_TNL_F_USE_ORIG_TCLASS | IP6_TNL_F_USE_ORIG_FWMARK))) {
10821084
/* enable the cache only only if the routing decision does

0 commit comments

Comments
 (0)