aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2018-03-31 15:58:54 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-31 23:25:39 -0400
commit1eec5d5670084ee644597bd26c25e22c69b9f748 (patch)
tree2b665adfd16baae97a8caa9426db3d168935a385
parent3e67f106f619dcfaf6f4e2039599bdb69848c714 (diff)
inet: frags: do not clone skb in ip_expire()
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 <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/ip_fragment.c16
1 files changed, 6 insertions, 10 deletions
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 053869f2c49b..fb185d9a5cc7 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)
143static void ip_expire(struct timer_list *t) 143static void ip_expire(struct timer_list *t)
144{ 144{
145 struct inet_frag_queue *frag = from_timer(frag, t, timer); 145 struct inet_frag_queue *frag = from_timer(frag, t, timer);
146 struct sk_buff *clone, *head;
147 const struct iphdr *iph; 146 const struct iphdr *iph;
147 struct sk_buff *head;
148 struct net *net; 148 struct net *net;
149 struct ipq *qp; 149 struct ipq *qp;
150 int err; 150 int err;
@@ -187,16 +187,12 @@ static void ip_expire(struct timer_list *t)
187 (skb_rtable(head)->rt_type != RTN_LOCAL)) 187 (skb_rtable(head)->rt_type != RTN_LOCAL))
188 goto out; 188 goto out;
189 189
190 clone = skb_clone(head, GFP_ATOMIC); 190 skb_get(head);
191 spin_unlock(&qp->q.lock);
192 icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
193 kfree_skb(head);
194 goto out_rcu_unlock;
191 195
192 /* Send an ICMP "Fragment Reassembly Timeout" message. */
193 if (clone) {
194 spin_unlock(&qp->q.lock);
195 icmp_send(clone, ICMP_TIME_EXCEEDED,
196 ICMP_EXC_FRAGTIME, 0);
197 consume_skb(clone);
198 goto out_rcu_unlock;
199 }
200out: 196out:
201 spin_unlock(&qp->q.lock); 197 spin_unlock(&qp->q.lock);
202out_rcu_unlock: 198out_rcu_unlock: