@@ -198,6 +198,7 @@ static void ip_expire(unsigned long arg)
198198 qp = container_of ((struct inet_frag_queue * ) arg , struct ipq , q );
199199 net = container_of (qp -> q .net , struct net , ipv4 .frags );
200200
201+ rcu_read_lock ();
201202 spin_lock (& qp -> q .lock );
202203
203204 if (qp -> q .flags & INET_FRAG_COMPLETE )
@@ -207,7 +208,7 @@ static void ip_expire(unsigned long arg)
207208 __IP_INC_STATS (net , IPSTATS_MIB_REASMFAILS );
208209
209210 if (!inet_frag_evicting (& qp -> q )) {
210- struct sk_buff * head = qp -> q .fragments ;
211+ struct sk_buff * clone , * head = qp -> q .fragments ;
211212 const struct iphdr * iph ;
212213 int err ;
213214
@@ -216,32 +217,40 @@ static void ip_expire(unsigned long arg)
216217 if (!(qp -> q .flags & INET_FRAG_FIRST_IN ) || !qp -> q .fragments )
217218 goto out ;
218219
219- rcu_read_lock ();
220220 head -> dev = dev_get_by_index_rcu (net , qp -> iif );
221221 if (!head -> dev )
222- goto out_rcu_unlock ;
222+ goto out ;
223+
223224
224225 /* skb has no dst, perform route lookup again */
225226 iph = ip_hdr (head );
226227 err = ip_route_input_noref (head , iph -> daddr , iph -> saddr ,
227228 iph -> tos , head -> dev );
228229 if (err )
229- goto out_rcu_unlock ;
230+ goto out ;
230231
231232 /* Only an end host needs to send an ICMP
232233 * "Fragment Reassembly Timeout" message, per RFC792.
233234 */
234235 if (frag_expire_skip_icmp (qp -> user ) &&
235236 (skb_rtable (head )-> rt_type != RTN_LOCAL ))
236- goto out_rcu_unlock ;
237+ goto out ;
238+
239+ clone = skb_clone (head , GFP_ATOMIC );
237240
238241 /* Send an ICMP "Fragment Reassembly Timeout" message. */
239- icmp_send (head , ICMP_TIME_EXCEEDED , ICMP_EXC_FRAGTIME , 0 );
240- out_rcu_unlock :
241- rcu_read_unlock ();
242+ if (clone ) {
243+ spin_unlock (& qp -> q .lock );
244+ icmp_send (clone , ICMP_TIME_EXCEEDED ,
245+ ICMP_EXC_FRAGTIME , 0 );
246+ consume_skb (clone );
247+ goto out_rcu_unlock ;
248+ }
242249 }
243250out :
244251 spin_unlock (& qp -> q .lock );
252+ out_rcu_unlock :
253+ rcu_read_unlock ();
245254 ipq_put (qp );
246255}
247256
0 commit comments