Commit 254d900b authored by Vasily Averin's avatar Vasily Averin Committed by David S. Miller

ipv4: ip_do_fragment: fix headroom tests

Some time ago David Woodhouse reported skb_under_panic
when we try to push ethernet header to fragmented ipv6 skbs.
It was fixed for ipv6 by Florian Westphal in
commit 1d325d21 ("ipv6: ip6_fragment: fix headroom tests and skb leak")

However similar problem still exist in ipv4.

It does not trigger skb_under_panic due paranoid check
in ip_finish_output2, however according to Alexey Kuznetsov
current state is abnormal and ip_fragment should be fixed too.
Signed-off-by: default avatarVasily Averin <vvs@virtuozzo.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e36fef66
...@@ -599,6 +599,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, ...@@ -599,6 +599,7 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
hlen = iph->ihl * 4; hlen = iph->ihl * 4;
mtu = mtu - hlen; /* Size of data space */ mtu = mtu - hlen; /* Size of data space */
IPCB(skb)->flags |= IPSKB_FRAG_COMPLETE; IPCB(skb)->flags |= IPSKB_FRAG_COMPLETE;
ll_rs = LL_RESERVED_SPACE(rt->dst.dev);
/* When frag_list is given, use it. First, check its validity: /* When frag_list is given, use it. First, check its validity:
* some transformers could create wrong frag_list or break existing * some transformers could create wrong frag_list or break existing
...@@ -614,14 +615,15 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, ...@@ -614,14 +615,15 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
if (first_len - hlen > mtu || if (first_len - hlen > mtu ||
((first_len - hlen) & 7) || ((first_len - hlen) & 7) ||
ip_is_fragment(iph) || ip_is_fragment(iph) ||
skb_cloned(skb)) skb_cloned(skb) ||
skb_headroom(skb) < ll_rs)
goto slow_path; goto slow_path;
skb_walk_frags(skb, frag) { skb_walk_frags(skb, frag) {
/* Correct geometry. */ /* Correct geometry. */
if (frag->len > mtu || if (frag->len > mtu ||
((frag->len & 7) && frag->next) || ((frag->len & 7) && frag->next) ||
skb_headroom(frag) < hlen) skb_headroom(frag) < hlen + ll_rs)
goto slow_path_clean; goto slow_path_clean;
/* Partially cloned skb? */ /* Partially cloned skb? */
...@@ -711,8 +713,6 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, ...@@ -711,8 +713,6 @@ int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
left = skb->len - hlen; /* Space per frame */ left = skb->len - hlen; /* Space per frame */
ptr = hlen; /* Where to start from */ ptr = hlen; /* Where to start from */
ll_rs = LL_RESERVED_SPACE(rt->dst.dev);
/* /*
* Fragment the datagram. * Fragment the datagram.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment