Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vti6: fix input path

Since commit 1625f4529957, vti6 is broken, all input packets are dropped
(LINUX_MIB_XFRMINNOSTATES is incremented).

XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 is set by vti6_rcv() before calling
xfrm6_rcv()/xfrm6_rcv_spi(), thus we cannot set to NULL that value in
xfrm6_rcv_spi().

A new function xfrm6_rcv_tnl() that enables to pass a value to
xfrm6_rcv_spi() is added, so that xfrm6_rcv() is not touched (this function
is used in several handlers).

CC: Alexey Kodanev <alexey.kodanev@oracle.com>
Fixes: 1625f4529957 ("net/xfrm_input: fix possible NULL deref of tunnel.ip6->parms.i_key")
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>

authored by

Nicolas Dichtel and committed by
Steffen Klassert
63c43787 b5884793

+16 -10
+3 -1
include/net/xfrm.h
··· 1540 1540 void xfrm4_local_error(struct sk_buff *skb, u32 mtu); 1541 1541 int xfrm6_extract_header(struct sk_buff *skb); 1542 1542 int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb); 1543 - int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi); 1543 + int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi, 1544 + struct ip6_tnl *t); 1544 1545 int xfrm6_transport_finish(struct sk_buff *skb, int async); 1546 + int xfrm6_rcv_tnl(struct sk_buff *skb, struct ip6_tnl *t); 1545 1547 int xfrm6_rcv(struct sk_buff *skb); 1546 1548 int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, 1547 1549 xfrm_address_t *saddr, u8 proto);
+1 -3
net/ipv6/ip6_vti.c
··· 321 321 goto discard; 322 322 } 323 323 324 - XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t; 325 - 326 324 rcu_read_unlock(); 327 325 328 - return xfrm6_rcv(skb); 326 + return xfrm6_rcv_tnl(skb, t); 329 327 } 330 328 rcu_read_unlock(); 331 329 return -EINVAL;
+11 -5
net/ipv6/xfrm6_input.c
··· 21 21 return xfrm6_extract_header(skb); 22 22 } 23 23 24 - int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) 24 + int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi, 25 + struct ip6_tnl *t) 25 26 { 26 - XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; 27 + XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t; 27 28 XFRM_SPI_SKB_CB(skb)->family = AF_INET6; 28 29 XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr); 29 30 return xfrm_input(skb, nexthdr, spi, 0); ··· 50 49 return -1; 51 50 } 52 51 53 - int xfrm6_rcv(struct sk_buff *skb) 52 + int xfrm6_rcv_tnl(struct sk_buff *skb, struct ip6_tnl *t) 54 53 { 55 54 return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], 56 - 0); 55 + 0, t); 56 + } 57 + EXPORT_SYMBOL(xfrm6_rcv_tnl); 58 + 59 + int xfrm6_rcv(struct sk_buff *skb) 60 + { 61 + return xfrm6_rcv_tnl(skb, NULL); 57 62 } 58 63 EXPORT_SYMBOL(xfrm6_rcv); 59 - 60 64 int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, 61 65 xfrm_address_t *saddr, u8 proto) 62 66 {
+1 -1
net/ipv6/xfrm6_tunnel.c
··· 236 236 __be32 spi; 237 237 238 238 spi = xfrm6_tunnel_spi_lookup(net, (const xfrm_address_t *)&iph->saddr); 239 - return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi); 239 + return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi, NULL); 240 240 } 241 241 242 242 static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,