aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Klassert <steffen.klassert@secunet.com>2014-09-16 04:08:40 -0400
committerSteffen Klassert <steffen.klassert@secunet.com>2014-09-16 04:08:40 -0400
commitf92ee61982d6da15a9e49664ecd6405a15a2ee56 (patch)
tree014f5e6b027f1446b5bda041382b30262868bf86
parent95cd6f488d164de462a8279e802a0ad05c33d167 (diff)
xfrm: Generate blackhole routes only from route lookup functions
Currently we genarate a blackhole route route whenever we have matching policies but can not resolve the states. Here we assume that dst_output() is called to kill the balckholed packets. Unfortunately this assumption is not true in all cases, so it is possible that these packets leave the system unwanted. We fix this by generating blackhole routes only from the route lookup functions, here we can guarantee a call to dst_output() afterwards. Fixes: 2774c131b1d ("xfrm: Handle blackhole route creation via afinfo.") Reported-by: Konstantinos Kolelis <k.kolelis@sirrix.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
-rw-r--r--include/net/dst.h15
-rw-r--r--net/ipv4/route.c6
-rw-r--r--net/ipv6/ip6_output.c4
-rw-r--r--net/xfrm/xfrm_policy.c18
4 files changed, 36 insertions, 7 deletions
diff --git a/include/net/dst.h b/include/net/dst.h
index 71c60f42be48..fa11c904d219 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -490,7 +490,16 @@ static inline struct dst_entry *xfrm_lookup(struct net *net,
490 int flags) 490 int flags)
491{ 491{
492 return dst_orig; 492 return dst_orig;
493} 493}
494
495static inline struct dst_entry *xfrm_lookup_route(struct net *net,
496 struct dst_entry *dst_orig,
497 const struct flowi *fl,
498 struct sock *sk,
499 int flags)
500{
501 return dst_orig;
502}
494 503
495static inline struct xfrm_state *dst_xfrm(const struct dst_entry *dst) 504static inline struct xfrm_state *dst_xfrm(const struct dst_entry *dst)
496{ 505{
@@ -502,6 +511,10 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
502 const struct flowi *fl, struct sock *sk, 511 const struct flowi *fl, struct sock *sk,
503 int flags); 512 int flags);
504 513
514struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig,
515 const struct flowi *fl, struct sock *sk,
516 int flags);
517
505/* skb attached with this dst needs transformation if dst->xfrm is valid */ 518/* skb attached with this dst needs transformation if dst->xfrm is valid */
506static inline struct xfrm_state *dst_xfrm(const struct dst_entry *dst) 519static inline struct xfrm_state *dst_xfrm(const struct dst_entry *dst)
507{ 520{
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index eaa4b000c7b4..173e7ea54c70 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2265,9 +2265,9 @@ struct rtable *ip_route_output_flow(struct net *net, struct flowi4 *flp4,
2265 return rt; 2265 return rt;
2266 2266
2267 if (flp4->flowi4_proto) 2267 if (flp4->flowi4_proto)
2268 rt = (struct rtable *) xfrm_lookup(net, &rt->dst, 2268 rt = (struct rtable *)xfrm_lookup_route(net, &rt->dst,
2269 flowi4_to_flowi(flp4), 2269 flowi4_to_flowi(flp4),
2270 sk, 0); 2270 sk, 0);
2271 2271
2272 return rt; 2272 return rt;
2273} 2273}
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 315a55d66079..0a3448b2888f 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1009,7 +1009,7 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
1009 if (final_dst) 1009 if (final_dst)
1010 fl6->daddr = *final_dst; 1010 fl6->daddr = *final_dst;
1011 1011
1012 return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); 1012 return xfrm_lookup_route(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0);
1013} 1013}
1014EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); 1014EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
1015 1015
@@ -1041,7 +1041,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
1041 if (final_dst) 1041 if (final_dst)
1042 fl6->daddr = *final_dst; 1042 fl6->daddr = *final_dst;
1043 1043
1044 return xfrm_lookup(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); 1044 return xfrm_lookup_route(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0);
1045} 1045}
1046EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); 1046EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
1047 1047
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index beeed602aeb3..7505674c9faa 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2138,7 +2138,7 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
2138 xfrm_pols_put(pols, drop_pols); 2138 xfrm_pols_put(pols, drop_pols);
2139 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); 2139 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
2140 2140
2141 return make_blackhole(net, family, dst_orig); 2141 return ERR_PTR(-EREMOTE);
2142 } 2142 }
2143 2143
2144 err = -EAGAIN; 2144 err = -EAGAIN;
@@ -2195,6 +2195,22 @@ dropdst:
2195} 2195}
2196EXPORT_SYMBOL(xfrm_lookup); 2196EXPORT_SYMBOL(xfrm_lookup);
2197 2197
2198/* Callers of xfrm_lookup_route() must ensure a call to dst_output().
2199 * Otherwise we may send out blackholed packets.
2200 */
2201struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig,
2202 const struct flowi *fl,
2203 struct sock *sk, int flags)
2204{
2205 struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk, flags);
2206
2207 if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE)
2208 return make_blackhole(net, dst_orig->ops->family, dst_orig);
2209
2210 return dst;
2211}
2212EXPORT_SYMBOL(xfrm_lookup_route);
2213
2198static inline int 2214static inline int
2199xfrm_secpath_reject(int idx, struct sk_buff *skb, const struct flowi *fl) 2215xfrm_secpath_reject(int idx, struct sk_buff *skb, const struct flowi *fl)
2200{ 2216{