ipv6: don't increase size when refragmenting forwarded ipv6 skbs
Subsystems (3)
PATCH v3 1/1 ipv6: don't increase size when refragmenting forwarded ipv6 skbs
since commit 6aafeef03b9d ("netfilter: push reasm skb through instead of original frag skbs") we will end up sometimes re-fragmenting skbs that we've reassembled.
ipv6 defrag preserves the original skbs using the skb frag list, i.e. as long as the skb frag list is preserved there is no problem since we keep original geometry of fragments intact.
However, in the rare case where the frag list is munged or skb is linearized, we might send larger fragments than what we originally received.
A router in the path might then send packet-too-big errors even if sender never sent fragments exceeding the reported mtu:
mtu 1500 - 1500:1400 - 1400:1280 - 1280
A R1 R2 B
1 - A sends to B, fragment size 1400
2 - R2 sends pkttoobig error for 1280
3 - A sends to B, fragment size 1280
4 - R2 sends pkttoobig error for 1280 again because it sees fragments of size 1400.
make sure ip6_fragment always caps MTU at largest packet size seen when defragmented skb is forwarded.
---
changes since v2:
update commit message: no problem unless skb frag list is munged/destroyed. move patch out of defrag patchset since this change is indepentent.
net/ipv6/ip6_output.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-)
net/ipv6/ip6_output.c +18 -11
@@ -564,18 +564,17 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb,/* We must not fragment if the socket is set to force MTU discovery * or if the skb it not generated by a local socket. */ -if (unlikely (!skb->ignore_df && skb->len > mtu) || - (IP6CB (skb)->frag_max_size && -IP6CB (skb)->frag_max_size > mtu)) { -if (skb->sk &&dst_allfrag (skb_dst (skb))) -sk_nocaps_add (skb->sk,NETIF_F_GSO_MASK ); +if (unlikely (!skb->ignore_df && skb->len > mtu)) + goto fail_toobig; - skb->dev =skb_dst (skb)->dev; -icmpv6_send (skb,ICMPV6_PKT_TOOBIG ,0 , mtu); -IP6_INC_STATS (net,ip6_dst_idev (skb_dst (skb)), -IPSTATS_MIB_FRAGFAILS ); -kfree_skb (skb); -return -EMSGSIZE ; +if (IP6CB (skb)->frag_max_size) { +if (IP6CB (skb)->frag_max_size > mtu) + goto fail_toobig; + +/* don't send fragments larger than what we received */ + mtu =IP6CB (skb)->frag_max_size; +if (mtu <IPV6_MIN_MTU ) + mtu =IPV6_MIN_MTU ; }if (np && np->frag_size < mtu) {
@@ -815,6 +814,14 @@ slow_path:consume_skb (skb);return err; +fail_toobig: +if (skb->sk &&dst_allfrag (skb_dst (skb))) +sk_nocaps_add (skb->sk,NETIF_F_GSO_MASK ); + + skb->dev =skb_dst (skb)->dev; +icmpv6_send (skb,ICMPV6_PKT_TOOBIG ,0 , mtu); + err = -EMSGSIZE ; + fail:IP6_INC_STATS (net,ip6_dst_idev (skb_dst (skb)),IPSTATS_MIB_FRAGFAILS );
Signature · 1 line
2.0.5
From: Florian Westphal <[email protected]>
Date: Fri, 22 May 2015 00:44:16 +0200
Quoted 23 lines
since commit
6aafeef03b9d("netfilter: push reasm skb through instead of original frag skbs") we will end up sometimes re-fragmenting skbs that we've reassembled.ipv6 defrag preserves the original skbs using the skb frag list, i.e. as long as the skb frag list is preserved there is no problem since we keep original geometry of fragments intact.
However, in the rare case where the frag list is munged or skb is linearized, we might send larger fragments than what we originally received.
A router in the path might then send packet-too-big errors even if sender never sent fragments exceeding the reported mtu:
mtu 1500 - 1500:1400 - 1400:1280 - 1280
A R1 R2 B1 - A sends to B, fragment size 1400
2 - R2 sends pkttoobig error for 1280
3 - A sends to B, fragment size 1280
4 - R2 sends pkttoobig error for 1280 again because it sees fragments of size 1400.
Quoted 5 lines
make sure
ip6_fragmentalways caps MTU at largest packet size seen when defragmented skb is forwarded.Signed-off-by Florian Westphal <[email protected]>
Applied to net-next, thanks.