diff options
author | Nicolas Dichtel <nicolas.dichtel@6wind.com> | 2010-09-03 01:13:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-09-07 16:57:21 -0400 |
commit | 1ee89bd0fe72e381c8e4ef887d53c19c8adc6c93 (patch) | |
tree | 3a73d6913b51dc91114443c5af2a1d44c59735c6 /net | |
parent | 70789d7052239992824628db8133de08dc78e593 (diff) |
netfilter: discard overlapping IPv6 fragment
RFC5722 prohibits reassembling IPv6 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/netfilter/nf_conntrack_reasm.c | 80 |
1 files changed, 15 insertions, 65 deletions
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 13ef5bc05cf5..578f3c1a16db 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -113,14 +113,6 @@ static void nf_skb_free(struct sk_buff *skb) | |||
113 | kfree_skb(NFCT_FRAG6_CB(skb)->orig); | 113 | kfree_skb(NFCT_FRAG6_CB(skb)->orig); |
114 | } | 114 | } |
115 | 115 | ||
116 | /* Memory Tracking Functions. */ | ||
117 | static void frag_kfree_skb(struct sk_buff *skb) | ||
118 | { | ||
119 | atomic_sub(skb->truesize, &nf_init_frags.mem); | ||
120 | nf_skb_free(skb); | ||
121 | kfree_skb(skb); | ||
122 | } | ||
123 | |||
124 | /* Destruction primitives. */ | 116 | /* Destruction primitives. */ |
125 | 117 | ||
126 | static __inline__ void fq_put(struct nf_ct_frag6_queue *fq) | 118 | static __inline__ void fq_put(struct nf_ct_frag6_queue *fq) |
@@ -282,66 +274,22 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | |||
282 | } | 274 | } |
283 | 275 | ||
284 | found: | 276 | found: |
285 | /* We found where to put this one. Check for overlap with | 277 | /* RFC5722, Section 4: |
286 | * preceding fragment, and, if needed, align things so that | 278 | * When reassembling an IPv6 datagram, if |
287 | * any overlaps are eliminated. | 279 | * one or more its constituent fragments is determined to be an |
288 | */ | 280 | * overlapping fragment, the entire datagram (and any constituent |
289 | if (prev) { | 281 | * fragments, including those not yet received) MUST be silently |
290 | int i = (NFCT_FRAG6_CB(prev)->offset + prev->len) - offset; | 282 | * discarded. |
291 | |||
292 | if (i > 0) { | ||
293 | offset += i; | ||
294 | if (end <= offset) { | ||
295 | pr_debug("overlap\n"); | ||
296 | goto err; | ||
297 | } | ||
298 | if (!pskb_pull(skb, i)) { | ||
299 | pr_debug("Can't pull\n"); | ||
300 | goto err; | ||
301 | } | ||
302 | if (skb->ip_summed != CHECKSUM_UNNECESSARY) | ||
303 | skb->ip_summed = CHECKSUM_NONE; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | /* Look for overlap with succeeding segments. | ||
308 | * If we can merge fragments, do it. | ||
309 | */ | 283 | */ |
310 | while (next && NFCT_FRAG6_CB(next)->offset < end) { | ||
311 | /* overlap is 'i' bytes */ | ||
312 | int i = end - NFCT_FRAG6_CB(next)->offset; | ||
313 | |||
314 | if (i < next->len) { | ||
315 | /* Eat head of the next overlapped fragment | ||
316 | * and leave the loop. The next ones cannot overlap. | ||
317 | */ | ||
318 | pr_debug("Eat head of the overlapped parts.: %d", i); | ||
319 | if (!pskb_pull(next, i)) | ||
320 | goto err; | ||
321 | 284 | ||
322 | /* next fragment */ | 285 | /* Check for overlap with preceding fragment. */ |
323 | NFCT_FRAG6_CB(next)->offset += i; | 286 | if (prev && |
324 | fq->q.meat -= i; | 287 | (NFCT_FRAG6_CB(prev)->offset + prev->len) - offset > 0) |
325 | if (next->ip_summed != CHECKSUM_UNNECESSARY) | 288 | goto discard_fq; |
326 | next->ip_summed = CHECKSUM_NONE; | ||
327 | break; | ||
328 | } else { | ||
329 | struct sk_buff *free_it = next; | ||
330 | |||
331 | /* Old fragmnet is completely overridden with | ||
332 | * new one drop it. | ||
333 | */ | ||
334 | next = next->next; | ||
335 | 289 | ||
336 | if (prev) | 290 | /* Look for overlap with succeeding segment. */ |
337 | prev->next = next; | 291 | if (next && NFCT_FRAG6_CB(next)->offset < end) |
338 | else | 292 | goto discard_fq; |
339 | fq->q.fragments = next; | ||
340 | |||
341 | fq->q.meat -= free_it->len; | ||
342 | frag_kfree_skb(free_it); | ||
343 | } | ||
344 | } | ||
345 | 293 | ||
346 | NFCT_FRAG6_CB(skb)->offset = offset; | 294 | NFCT_FRAG6_CB(skb)->offset = offset; |
347 | 295 | ||
@@ -371,6 +319,8 @@ found: | |||
371 | write_unlock(&nf_frags.lock); | 319 | write_unlock(&nf_frags.lock); |
372 | return 0; | 320 | return 0; |
373 | 321 | ||
322 | discard_fq: | ||
323 | fq_kill(fq); | ||
374 | err: | 324 | err: |
375 | return -1; | 325 | return -1; |
376 | } | 326 | } |