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 | |
| 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>
| -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 | } | 
