don't bother with pathological cases, they only waste cycles. IPv6 requires a minimum MTU of 1280 so we should never see fragments smaller than this (except last frag).
For IPv4, in practice, we could probably also adopt a higher limit, but for now use ipv4 min mtu (68). Cc: Peter Oskolkov <p...@google.com> Cc: Eric Dumazet <eduma...@google.com> Signed-off-by: Florian Westphal <f...@strlen.de> --- net/ipv4/ip_fragment.c | 5 +++++ net/ipv6/netfilter/nf_conntrack_reasm.c | 4 ++++ net/ipv6/reassembly.c | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 8e9528ebaa8e..19aa10abc6ab 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -605,6 +605,10 @@ int ip_defrag(struct net *net, struct sk_buff *skb, u32 user) int vif = l3mdev_master_ifindex_rcu(dev); struct ipq *qp; + if (-skb_network_offset(skb) + skb->len < IPV4_MIN_MTU && + ip_hdr(skb)->frag_off & htons(IP_MF)) + goto drop; + __IP_INC_STATS(net, IPSTATS_MIB_REASMREQDS); skb_orphan(skb); @@ -622,6 +626,7 @@ int ip_defrag(struct net *net, struct sk_buff *skb, u32 user) return ret; } +drop: __IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS); kfree_skb(skb); return -ENOMEM; diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 0610bdab721c..c121d534d321 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -557,6 +557,10 @@ int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user) hdr = ipv6_hdr(skb); fhdr = (struct frag_hdr *)skb_transport_header(skb); + if (-skb_network_offset(skb) + skb->len < IPV6_MIN_MTU && + fhdr->frag_off & htons(IP6_MF)) + return -EINVAL; + skb_orphan(skb); fq = fq_find(net, fhdr->identification, user, hdr, skb->dev ? skb->dev->ifindex : 0); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 6edd2ac8ae4b..ff00ada6128f 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -455,6 +455,10 @@ static int ipv6_frag_rcv(struct sk_buff *skb) return 1; } + if (-skb_network_offset(skb) + skb->len < IPV6_MIN_MTU && + fhdr->frag_off & htons(IP6_MF)) + goto fail_hdr; + iif = skb->dev ? skb->dev->ifindex : 0; fq = fq_find(net, fhdr->identification, hdr, iif); if (fq) { -- 2.16.4