summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2008-02-15 01:55:06 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2008-02-25 16:18:42 -0800
commit8f08540f032d07a7fb8f7576140ca426c55396f3 (patch)
treeba2be34ccf8e6fa298a35aafbb4aacdcc2bd7c0f
parent4450ae03346faceb80a45b4d696c15f981080916 (diff)
INET: Prevent out-of-sync truesize on ip_fragment slow path
Upstream commit: 29ffe1a5c52dae13b6efead97aab9b058f38fce4 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> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-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 bc9e57550e86..61c60cf722fb 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -462,6 +462,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
if (skb_shinfo(skb)->frag_list) {
struct sk_buff *frag;
int first_len = skb_pagelen(skb);
+ int truesizes = 0;
if (first_len - hlen > mtu ||
((first_len - hlen) & 7) ||
@@ -485,7 +486,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
sock_hold(skb->sk);
frag->sk = skb->sk;
frag->destructor = sock_wfree;
- skb->truesize -= frag->truesize;
+ truesizes += frag->truesize;
}
}
@@ -496,6 +497,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
frag = skb_shinfo(skb)->frag_list;
skb_shinfo(skb)->frag_list = NULL;
skb->data_len = first_len - skb_headlen(skb);
+ skb->truesize -= truesizes;
skb->len = first_len;
iph->tot_len = htons(first_len);
iph->frag_off = htons(IP_MF);
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 3bef30e4a23d..2f59baa53c6f 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -609,6 +609,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
if (skb_shinfo(skb)->frag_list) {
int first_len = skb_pagelen(skb);
+ int truesizes = 0;
if (first_len - hlen > mtu ||
((first_len - hlen) & 7) ||
@@ -631,7 +632,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
sock_hold(skb->sk);
frag->sk = skb->sk;
frag->destructor = sock_wfree;
- skb->truesize -= frag->truesize;
+ truesizes += frag->truesize;
}
}
@@ -662,6 +663,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
first_len = skb_pagelen(skb);
skb->data_len = first_len - skb_headlen(skb);
+ skb->truesize -= truesizes;
skb->len = first_len;
ipv6_hdr(skb)->payload_len = htons(first_len -
sizeof(struct ipv6hdr));