@@ -198,6 +198,7 @@ static void ip_expire(unsigned long arg)
198
198
qp = container_of ((struct inet_frag_queue * ) arg , struct ipq , q );
199
199
net = container_of (qp -> q .net , struct net , ipv4 .frags );
200
200
201
+ rcu_read_lock ();
201
202
spin_lock (& qp -> q .lock );
202
203
203
204
if (qp -> q .flags & INET_FRAG_COMPLETE )
@@ -207,7 +208,7 @@ static void ip_expire(unsigned long arg)
207
208
__IP_INC_STATS (net , IPSTATS_MIB_REASMFAILS );
208
209
209
210
if (!inet_frag_evicting (& qp -> q )) {
210
- struct sk_buff * head = qp -> q .fragments ;
211
+ struct sk_buff * clone , * head = qp -> q .fragments ;
211
212
const struct iphdr * iph ;
212
213
int err ;
213
214
@@ -216,32 +217,40 @@ static void ip_expire(unsigned long arg)
216
217
if (!(qp -> q .flags & INET_FRAG_FIRST_IN ) || !qp -> q .fragments )
217
218
goto out ;
218
219
219
- rcu_read_lock ();
220
220
head -> dev = dev_get_by_index_rcu (net , qp -> iif );
221
221
if (!head -> dev )
222
- goto out_rcu_unlock ;
222
+ goto out ;
223
+
223
224
224
225
/* skb has no dst, perform route lookup again */
225
226
iph = ip_hdr (head );
226
227
err = ip_route_input_noref (head , iph -> daddr , iph -> saddr ,
227
228
iph -> tos , head -> dev );
228
229
if (err )
229
- goto out_rcu_unlock ;
230
+ goto out ;
230
231
231
232
/* Only an end host needs to send an ICMP
232
233
* "Fragment Reassembly Timeout" message, per RFC792.
233
234
*/
234
235
if (frag_expire_skip_icmp (qp -> user ) &&
235
236
(skb_rtable (head )-> rt_type != RTN_LOCAL ))
236
- goto out_rcu_unlock ;
237
+ goto out ;
238
+
239
+ clone = skb_clone (head , GFP_ATOMIC );
237
240
238
241
/* 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
+ }
242
249
}
243
250
out :
244
251
spin_unlock (& qp -> q .lock );
252
+ out_rcu_unlock :
253
+ rcu_read_unlock ();
245
254
ipq_put (qp );
246
255
}
247
256
0 commit comments