diff options
author | thomas.zeitlhofer+lkml@ze-it.at <thomas.zeitlhofer+lkml@ze-it.at> | 2016-09-07 14:40:38 -0400 |
---|---|---|
committer | Steffen Klassert <steffen.klassert@secunet.com> | 2016-09-09 03:02:08 -0400 |
commit | 1fb81e09d487656aa23f2acb1232c7f56b4c2367 (patch) | |
tree | 72a7c89c15f827148d5eab8a1136aa565a7f4988 /net/ipv4 | |
parent | 2f30ea5090cbc57ea573cdc66421264b3de3fb0a (diff) |
vti: use right inner_mode for inbound inter address family policy checks
In case of inter address family tunneling (IPv6 over vti4 or IPv4 over
vti6), the inbound policy checks in vti_rcv_cb() and vti6_rcv_cb() are
using the wrong address family. As a result, all inbound inter address
family traffic is dropped.
Use the xfrm_ip2inner_mode() helper, as done in xfrm_input() (i.e., also
increment LINUX_MIB_XFRMINSTATEMODEERROR in case of error), to select the
inner_mode that contains the right address family for the inbound policy
checks.
Signed-off-by: Thomas Zeitlhofer <thomas.zeitlhofer+lkml@ze-it.at>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/ip_vti.c | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index cc701fa70b12..5d7944f394d9 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c | |||
@@ -88,6 +88,7 @@ static int vti_rcv_cb(struct sk_buff *skb, int err) | |||
88 | struct net_device *dev; | 88 | struct net_device *dev; |
89 | struct pcpu_sw_netstats *tstats; | 89 | struct pcpu_sw_netstats *tstats; |
90 | struct xfrm_state *x; | 90 | struct xfrm_state *x; |
91 | struct xfrm_mode *inner_mode; | ||
91 | struct ip_tunnel *tunnel = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4; | 92 | struct ip_tunnel *tunnel = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4; |
92 | u32 orig_mark = skb->mark; | 93 | u32 orig_mark = skb->mark; |
93 | int ret; | 94 | int ret; |
@@ -105,7 +106,19 @@ static int vti_rcv_cb(struct sk_buff *skb, int err) | |||
105 | } | 106 | } |
106 | 107 | ||
107 | x = xfrm_input_state(skb); | 108 | x = xfrm_input_state(skb); |
108 | family = x->inner_mode->afinfo->family; | 109 | |
110 | inner_mode = x->inner_mode; | ||
111 | |||
112 | if (x->sel.family == AF_UNSPEC) { | ||
113 | inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); | ||
114 | if (inner_mode == NULL) { | ||
115 | XFRM_INC_STATS(dev_net(skb->dev), | ||
116 | LINUX_MIB_XFRMINSTATEMODEERROR); | ||
117 | return -EINVAL; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | family = inner_mode->afinfo->family; | ||
109 | 122 | ||
110 | skb->mark = be32_to_cpu(tunnel->parms.i_key); | 123 | skb->mark = be32_to_cpu(tunnel->parms.i_key); |
111 | ret = xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family); | 124 | ret = xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family); |