From mboxrd@z Thu Jan 1 00:00:00 1970 From: Eric Dumazet Subject: [PATCH v4 net-next 13/19] inet: frags: do not clone skb in ip_expire() Date: Sat, 31 Mar 2018 12:58:54 -0700 Message-ID: <20180331195900.183604-14-edumazet@google.com> References: <20180331195900.183604-1-edumazet@google.com> Cc: netdev , Florian Westphal , Herbert Xu , Thomas Graf , Jesper Dangaard Brouer , Alexander Aring , Stefan Schmidt , Kirill Tkhai , Eric Dumazet , Eric Dumazet To: "David S . Miller" Return-path: Received: from mail-pg0-f65.google.com ([74.125.83.65]:33092 "EHLO mail-pg0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752924AbeCaT7p (ORCPT ); Sat, 31 Mar 2018 15:59:45 -0400 Received: by mail-pg0-f65.google.com with SMTP id i194so7012996pgd.0 for ; Sat, 31 Mar 2018 12:59:45 -0700 (PDT) In-Reply-To: <20180331195900.183604-1-edumazet@google.com> Sender: netdev-owner@vger.kernel.org List-ID: An skb_clone() was added in commit ec4fbd64751d ("inet: frag: release spinlock before calling icmp_send()") While fixing the bug at that time, it also added a very high cost for DDOS frags, as the ICMP rate limit is applied after this expensive operation (skb_clone() + consume_skb(), implying memory allocations, copy, and freeing) We can use skb_get(head) here, all we want is to make sure skb wont be freed by another cpu. Signed-off-by: Eric Dumazet --- net/ipv4/ip_fragment.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 053869f2c49b9fd7a87316f1ef1416568b1bf508..fb185d9a5cc771778fb650695e2d9894724efc23 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -143,8 +143,8 @@ static bool frag_expire_skip_icmp(u32 user) static void ip_expire(struct timer_list *t) { struct inet_frag_queue *frag = from_timer(frag, t, timer); - struct sk_buff *clone, *head; const struct iphdr *iph; + struct sk_buff *head; struct net *net; struct ipq *qp; int err; @@ -187,16 +187,12 @@ static void ip_expire(struct timer_list *t) (skb_rtable(head)->rt_type != RTN_LOCAL)) goto out; - clone = skb_clone(head, GFP_ATOMIC); + skb_get(head); + spin_unlock(&qp->q.lock); + icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); + kfree_skb(head); + goto out_rcu_unlock; - /* Send an ICMP "Fragment Reassembly Timeout" message. */ - if (clone) { - spin_unlock(&qp->q.lock); - icmp_send(clone, ICMP_TIME_EXCEEDED, - ICMP_EXC_FRAGTIME, 0); - consume_skb(clone); - goto out_rcu_unlock; - } out: spin_unlock(&qp->q.lock); out_rcu_unlock: -- 2.17.0.rc1.321.gba9d0f2565-goog