Commit 9ad1a959ac71423224aa8f248af3cc258e54e46a
Committed by
Greg Kroah-Hartman
1 parent
c75e4b05b5
ipv4: try to cache dst_entries which would cause a redirect
[ Upstream commit df4d92549f23e1c037e83323aff58a21b3de7fe0 ] 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 3 changed files with 13 additions and 10 deletions Side-by-side Diff
include/net/ip.h
... | ... | @@ -39,11 +39,12 @@ |
39 | 39 | struct ip_options opt; /* Compiled IP options */ |
40 | 40 | unsigned char flags; |
41 | 41 | |
42 | -#define IPSKB_FORWARDED 1 | |
43 | -#define IPSKB_XFRM_TUNNEL_SIZE 2 | |
44 | -#define IPSKB_XFRM_TRANSFORMED 4 | |
45 | -#define IPSKB_FRAG_COMPLETE 8 | |
46 | -#define IPSKB_REROUTED 16 | |
42 | +#define IPSKB_FORWARDED BIT(0) | |
43 | +#define IPSKB_XFRM_TUNNEL_SIZE BIT(1) | |
44 | +#define IPSKB_XFRM_TRANSFORMED BIT(2) | |
45 | +#define IPSKB_FRAG_COMPLETE BIT(3) | |
46 | +#define IPSKB_REROUTED BIT(4) | |
47 | +#define IPSKB_DOREDIRECT BIT(5) | |
47 | 48 | |
48 | 49 | u16 frag_max_size; |
49 | 50 | }; |
net/ipv4/ip_forward.c
... | ... | @@ -129,7 +129,8 @@ |
129 | 129 | * We now generate an ICMP HOST REDIRECT giving the route |
130 | 130 | * we calculated. |
131 | 131 | */ |
132 | - if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb_sec_path(skb)) | |
132 | + if (IPCB(skb)->flags & IPSKB_DOREDIRECT && !opt->srr && | |
133 | + !skb_sec_path(skb)) | |
133 | 134 | ip_rt_send_redirect(skb); |
134 | 135 | |
135 | 136 | skb->priority = rt_tos2priority(iph->tos); |
net/ipv4/route.c
... | ... | @@ -1554,11 +1554,10 @@ |
1554 | 1554 | |
1555 | 1555 | do_cache = res->fi && !itag; |
1556 | 1556 | if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) && |
1557 | + skb->protocol == htons(ETH_P_IP) && | |
1557 | 1558 | (IN_DEV_SHARED_MEDIA(out_dev) || |
1558 | - inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) { | |
1559 | - flags |= RTCF_DOREDIRECT; | |
1560 | - do_cache = false; | |
1561 | - } | |
1559 | + inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) | |
1560 | + IPCB(skb)->flags |= IPSKB_DOREDIRECT; | |
1562 | 1561 | |
1563 | 1562 | if (skb->protocol != htons(ETH_P_IP)) { |
1564 | 1563 | /* Not IP (i.e. ARP). Do not create route, if it is |
... | ... | @@ -2303,6 +2302,8 @@ |
2303 | 2302 | r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; |
2304 | 2303 | if (rt->rt_flags & RTCF_NOTIFY) |
2305 | 2304 | r->rtm_flags |= RTM_F_NOTIFY; |
2305 | + if (IPCB(skb)->flags & IPSKB_DOREDIRECT) | |
2306 | + r->rtm_flags |= RTCF_DOREDIRECT; | |
2306 | 2307 | |
2307 | 2308 | if (nla_put_be32(skb, RTA_DST, dst)) |
2308 | 2309 | goto nla_put_failure; |