aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2010-09-03 01:13:05 -0400
committerDavid S. Miller <davem@davemloft.net>2010-09-07 16:57:21 -0400
commit70789d7052239992824628db8133de08dc78e593 (patch)
treec1fb08a04f4f3a266165405d2f5d606ddff30479 /net
parentdeabc772f39405054a438d711f408d2d94d26d96 (diff)
ipv6: discard overlapping fragment
RFC5722 prohibits reassembling fragments when some data overlaps. Bug spotted by Zhang Zuotao <zuotao.zhang@6wind.com>. Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/reassembly.c71
1 files changed, 15 insertions, 56 deletions
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 545c4141b755..64cfef1b0a4c 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -149,13 +149,6 @@ int ip6_frag_match(struct inet_frag_queue *q, void *a)
149} 149}
150EXPORT_SYMBOL(ip6_frag_match); 150EXPORT_SYMBOL(ip6_frag_match);
151 151
152/* Memory Tracking Functions. */
153static void frag_kfree_skb(struct netns_frags *nf, struct sk_buff *skb)
154{
155 atomic_sub(skb->truesize, &nf->mem);
156 kfree_skb(skb);
157}
158
159void ip6_frag_init(struct inet_frag_queue *q, void *a) 152void ip6_frag_init(struct inet_frag_queue *q, void *a)
160{ 153{
161 struct frag_queue *fq = container_of(q, struct frag_queue, q); 154 struct frag_queue *fq = container_of(q, struct frag_queue, q);
@@ -346,58 +339,22 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
346 } 339 }
347 340
348found: 341found:
349 /* We found where to put this one. Check for overlap with 342 /* RFC5722, Section 4:
350 * preceding fragment, and, if needed, align things so that 343 * When reassembling an IPv6 datagram, if
351 * any overlaps are eliminated. 344 * one or more its constituent fragments is determined to be an
345 * overlapping fragment, the entire datagram (and any constituent
346 * fragments, including those not yet received) MUST be silently
347 * discarded.
352 */ 348 */
353 if (prev) {
354 int i = (FRAG6_CB(prev)->offset + prev->len) - offset;
355 349
356 if (i > 0) { 350 /* Check for overlap with preceding fragment. */
357 offset += i; 351 if (prev &&
358 if (end <= offset) 352 (FRAG6_CB(prev)->offset + prev->len) - offset > 0)
359 goto err; 353 goto discard_fq;
360 if (!pskb_pull(skb, i))
361 goto err;
362 if (skb->ip_summed != CHECKSUM_UNNECESSARY)
363 skb->ip_summed = CHECKSUM_NONE;
364 }
365 }
366 354
367 /* Look for overlap with succeeding segments. 355 /* Look for overlap with succeeding segment. */
368 * If we can merge fragments, do it. 356 if (next && FRAG6_CB(next)->offset < end)
369 */ 357 goto discard_fq;
370 while (next && FRAG6_CB(next)->offset < end) {
371 int i = end - FRAG6_CB(next)->offset; /* overlap is 'i' bytes */
372
373 if (i < next->len) {
374 /* Eat head of the next overlapped fragment
375 * and leave the loop. The next ones cannot overlap.
376 */
377 if (!pskb_pull(next, i))
378 goto err;
379 FRAG6_CB(next)->offset += i; /* next fragment */
380 fq->q.meat -= i;
381 if (next->ip_summed != CHECKSUM_UNNECESSARY)
382 next->ip_summed = CHECKSUM_NONE;
383 break;
384 } else {
385 struct sk_buff *free_it = next;
386
387 /* Old fragment is completely overridden with
388 * new one drop it.
389 */
390 next = next->next;
391
392 if (prev)
393 prev->next = next;
394 else
395 fq->q.fragments = next;
396
397 fq->q.meat -= free_it->len;
398 frag_kfree_skb(fq->q.net, free_it);
399 }
400 }
401 358
402 FRAG6_CB(skb)->offset = offset; 359 FRAG6_CB(skb)->offset = offset;
403 360
@@ -436,6 +393,8 @@ found:
436 write_unlock(&ip6_frags.lock); 393 write_unlock(&ip6_frags.lock);
437 return -1; 394 return -1;
438 395
396discard_fq:
397 fq_kill(fq);
439err: 398err:
440 IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 399 IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
441 IPSTATS_MIB_REASMFAILS); 400 IPSTATS_MIB_REASMFAILS);