aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2008-01-28 23:45:20 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-31 22:27:07 -0500
commit29ffe1a5c52dae13b6efead97aab9b058f38fce4 (patch)
treebcca1391f02a01cf1b2d5942a06d392ac0f5be11
parent1987e7b4855fcb6a866d3279ee9f2890491bc34d (diff)
[INET]: Prevent out-of-sync truesize on ip_fragment slow path
When ip_fragment has to hit the slow path the value of skb->truesize may go out of sync because we would have updated it without changing the packet length. This violates the constraints on truesize. This patch postpones the update of skb->truesize to prevent this. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/ip_output.c4
-rw-r--r--net/ipv6/ip6_output.c4
2 files changed, 6 insertions, 2 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 18070ca65771..6e4d5f493bf9 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -476,6 +476,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
476 if (skb_shinfo(skb)->frag_list) { 476 if (skb_shinfo(skb)->frag_list) {
477 struct sk_buff *frag; 477 struct sk_buff *frag;
478 int first_len = skb_pagelen(skb); 478 int first_len = skb_pagelen(skb);
479 int truesizes = 0;
479 480
480 if (first_len - hlen > mtu || 481 if (first_len - hlen > mtu ||
481 ((first_len - hlen) & 7) || 482 ((first_len - hlen) & 7) ||
@@ -499,7 +500,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
499 sock_hold(skb->sk); 500 sock_hold(skb->sk);
500 frag->sk = skb->sk; 501 frag->sk = skb->sk;
501 frag->destructor = sock_wfree; 502 frag->destructor = sock_wfree;
502 skb->truesize -= frag->truesize; 503 truesizes += frag->truesize;
503 } 504 }
504 } 505 }
505 506
@@ -510,6 +511,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
510 frag = skb_shinfo(skb)->frag_list; 511 frag = skb_shinfo(skb)->frag_list;
511 skb_shinfo(skb)->frag_list = NULL; 512 skb_shinfo(skb)->frag_list = NULL;
512 skb->data_len = first_len - skb_headlen(skb); 513 skb->data_len = first_len - skb_headlen(skb);
514 skb->truesize -= truesizes;
513 skb->len = first_len; 515 skb->len = first_len;
514 iph->tot_len = htons(first_len); 516 iph->tot_len = htons(first_len);
515 iph->frag_off = htons(IP_MF); 517 iph->frag_off = htons(IP_MF);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 15c4f6cee3e6..cfe9e707883c 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -636,6 +636,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
636 636
637 if (skb_shinfo(skb)->frag_list) { 637 if (skb_shinfo(skb)->frag_list) {
638 int first_len = skb_pagelen(skb); 638 int first_len = skb_pagelen(skb);
639 int truesizes = 0;
639 640
640 if (first_len - hlen > mtu || 641 if (first_len - hlen > mtu ||
641 ((first_len - hlen) & 7) || 642 ((first_len - hlen) & 7) ||
@@ -658,7 +659,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
658 sock_hold(skb->sk); 659 sock_hold(skb->sk);
659 frag->sk = skb->sk; 660 frag->sk = skb->sk;
660 frag->destructor = sock_wfree; 661 frag->destructor = sock_wfree;
661 skb->truesize -= frag->truesize; 662 truesizes += frag->truesize;
662 } 663 }
663 } 664 }
664 665
@@ -689,6 +690,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
689 690
690 first_len = skb_pagelen(skb); 691 first_len = skb_pagelen(skb);
691 skb->data_len = first_len - skb_headlen(skb); 692 skb->data_len = first_len - skb_headlen(skb);
693 skb->truesize -= truesizes;
692 skb->len = first_len; 694 skb->len = first_len;
693 ipv6_hdr(skb)->payload_len = htons(first_len - 695 ipv6_hdr(skb)->payload_len = htons(first_len -
694 sizeof(struct ipv6hdr)); 696 sizeof(struct ipv6hdr));