diff options
author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2015-01-23 12:01:26 +0100 |
---|---|---|
committer | Brett Rogers <brettrogers11@gmail.com> | 2016-02-22 16:35:36 -0800 |
commit | 13696bfd759e22d99eab7a81b18341b05772aad4 (patch) | |
tree | f4ef748cdf60bfc40761a1a66c19fd3b04ea77ab | |
parent | 5080905535c3c977a96a0ef7faaa5095dafd7760 (diff) | |
download | kernel_samsung_smdk4412-13696bfd759e22d99eab7a81b18341b05772aad4.tar.gz kernel_samsung_smdk4412-13696bfd759e22d99eab7a81b18341b05772aad4.tar.bz2 kernel_samsung_smdk4412-13696bfd759e22d99eab7a81b18341b05772aad4.zip |
ipv4: try to cache dst_entries which would cause a redirect
Not caching dst_entries which cause redirects could be exploited by hosts
on the same subnet, causing a severe DoS attack. This effect aggravated
since commit f88649721268999 ("ipv4: fix dst race in sk_dst_get()").
Lookups causing redirects will be allocated with DST_NOCACHE set which
will force dst_release to free them via RCU. Unfortunately waiting for
RCU grace period just takes too long, we can end up with >1M dst_entries
waiting to be released and the system will run OOM. rcuos threads cannot
catch up under high softirq load.
Attaching the flag to emit a redirect later on to the specific skb allows
us to cache those dst_entries thus reducing the pressure on allocation
and deallocation.
This issue was discovered by Marcelo Leitner.
Cc: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Marcelo Leitner <mleitner@redhat.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: David S. Miller <davem@davemloft.net>
Conflicts:
include/net/ip.h
net/ipv4/route.c
Change-Id: I53e4b500a4db2f5fece937a42a3bd810b2640c44
-rw-r--r-- | include/net/ip.h | 11 | ||||
-rw-r--r-- | net/ipv4/ip_forward.c | 3 | ||||
-rw-r--r-- | net/ipv4/route.c | 5 |
3 files changed, 12 insertions, 7 deletions
diff --git a/include/net/ip.h b/include/net/ip.h index 29e31ae2d43..8729846cc3c 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -37,11 +37,12 @@ struct inet_skb_parm { struct ip_options opt; /* Compiled IP options */ unsigned char flags; -#define IPSKB_FORWARDED 1 -#define IPSKB_XFRM_TUNNEL_SIZE 2 -#define IPSKB_XFRM_TRANSFORMED 4 -#define IPSKB_FRAG_COMPLETE 8 -#define IPSKB_REROUTED 16 +#define IPSKB_FORWARDED BIT(0) +#define IPSKB_XFRM_TUNNEL_SIZE BIT(1) +#define IPSKB_XFRM_TRANSFORMED BIT(2) +#define IPSKB_FRAG_COMPLETE BIT(3) +#define IPSKB_REROUTED BIT(4) +#define IPSKB_DOREDIRECT BIT(5) }; static inline unsigned int ip_hdrlen(const struct sk_buff *skb) diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 29a07b6c716..0ee2d50c634 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -107,7 +107,8 @@ int ip_forward(struct sk_buff *skb) * We now generate an ICMP HOST REDIRECT giving the route * we calculated. */ - if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb_sec_path(skb)) + if (IPCB(skb)->flags & IPSKB_DOREDIRECT && !opt->srr && + !skb_sec_path(skb)) ip_rt_send_redirect(skb); skb->priority = rt_tos2priority(iph->tos); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index cd404159d49..666b48616ac 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2123,9 +2123,10 @@ static int __mkroute_input(struct sk_buff *skb, flags |= RTCF_DIRECTSRC; if (out_dev == in_dev && err && + skb->protocol == htons(ETH_P_IP) && (IN_DEV_SHARED_MEDIA(out_dev) || inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) - flags |= RTCF_DOREDIRECT; + IPCB(skb)->flags |= IPSKB_DOREDIRECT; if (skb->protocol != htons(ETH_P_IP)) { /* Not IP (i.e. ARP). Do not create route, if it is @@ -2949,6 +2950,8 @@ static int rt_fill_info(struct net *net, r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; if (rt->rt_flags & RTCF_NOTIFY) r->rtm_flags |= RTM_F_NOTIFY; + if (IPCB(skb)->flags & IPSKB_DOREDIRECT) + r->rtm_flags |= RTCF_DOREDIRECT; NLA_PUT_BE32(skb, RTA_DST, rt->rt_dst); |