[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>
This commit is contained in:
committed by
David S. Miller
parent
1987e7b485
commit
29ffe1a5c5
@@ -476,6 +476,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
|
|||||||
if (skb_shinfo(skb)->frag_list) {
|
if (skb_shinfo(skb)->frag_list) {
|
||||||
struct sk_buff *frag;
|
struct sk_buff *frag;
|
||||||
int first_len = skb_pagelen(skb);
|
int first_len = skb_pagelen(skb);
|
||||||
|
int truesizes = 0;
|
||||||
|
|
||||||
if (first_len - hlen > mtu ||
|
if (first_len - hlen > mtu ||
|
||||||
((first_len - hlen) & 7) ||
|
((first_len - hlen) & 7) ||
|
||||||
@@ -499,7 +500,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
|
|||||||
sock_hold(skb->sk);
|
sock_hold(skb->sk);
|
||||||
frag->sk = skb->sk;
|
frag->sk = skb->sk;
|
||||||
frag->destructor = sock_wfree;
|
frag->destructor = sock_wfree;
|
||||||
skb->truesize -= frag->truesize;
|
truesizes += frag->truesize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,6 +511,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
|
|||||||
frag = skb_shinfo(skb)->frag_list;
|
frag = skb_shinfo(skb)->frag_list;
|
||||||
skb_shinfo(skb)->frag_list = NULL;
|
skb_shinfo(skb)->frag_list = NULL;
|
||||||
skb->data_len = first_len - skb_headlen(skb);
|
skb->data_len = first_len - skb_headlen(skb);
|
||||||
|
skb->truesize -= truesizes;
|
||||||
skb->len = first_len;
|
skb->len = first_len;
|
||||||
iph->tot_len = htons(first_len);
|
iph->tot_len = htons(first_len);
|
||||||
iph->frag_off = htons(IP_MF);
|
iph->frag_off = htons(IP_MF);
|
||||||
|
@@ -636,6 +636,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
|||||||
|
|
||||||
if (skb_shinfo(skb)->frag_list) {
|
if (skb_shinfo(skb)->frag_list) {
|
||||||
int first_len = skb_pagelen(skb);
|
int first_len = skb_pagelen(skb);
|
||||||
|
int truesizes = 0;
|
||||||
|
|
||||||
if (first_len - hlen > mtu ||
|
if (first_len - hlen > mtu ||
|
||||||
((first_len - hlen) & 7) ||
|
((first_len - hlen) & 7) ||
|
||||||
@@ -658,7 +659,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
|||||||
sock_hold(skb->sk);
|
sock_hold(skb->sk);
|
||||||
frag->sk = skb->sk;
|
frag->sk = skb->sk;
|
||||||
frag->destructor = sock_wfree;
|
frag->destructor = sock_wfree;
|
||||||
skb->truesize -= frag->truesize;
|
truesizes += frag->truesize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -689,6 +690,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
|
|||||||
|
|
||||||
first_len = skb_pagelen(skb);
|
first_len = skb_pagelen(skb);
|
||||||
skb->data_len = first_len - skb_headlen(skb);
|
skb->data_len = first_len - skb_headlen(skb);
|
||||||
|
skb->truesize -= truesizes;
|
||||||
skb->len = first_len;
|
skb->len = first_len;
|
||||||
ipv6_hdr(skb)->payload_len = htons(first_len -
|
ipv6_hdr(skb)->payload_len = htons(first_len -
|
||||||
sizeof(struct ipv6hdr));
|
sizeof(struct ipv6hdr));
|
||||||
|
Reference in New Issue
Block a user