From patchwork Thu Aug 2 23:34:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Oskolkov X-Patchwork-Id: 953002 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.b="pzbJe/v2"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 41hRNb4RTNz9s5c for ; Fri, 3 Aug 2018 09:34:55 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732090AbeHCB2L (ORCPT ); Thu, 2 Aug 2018 21:28:11 -0400 Received: from mail-io0-f201.google.com ([209.85.223.201]:36939 "EHLO mail-io0-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727053AbeHCB2L (ORCPT ); Thu, 2 Aug 2018 21:28:11 -0400 Received: by mail-io0-f201.google.com with SMTP id l5-v6so2825459ioh.4 for ; Thu, 02 Aug 2018 16:34:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=pWztRfk0KM6ax3oD+E1yf8tb0/ZS2kY2fLFPdKSwh9g=; b=pzbJe/v2JwE1LV6K/jR9oFUxc/cXTdSoK0zf4WSwtkPOLKBW1/qxZtdTffL20mJohR kBd0ivAytT2tf1R1jFAzWCTI0dxmMcT9wzyGIaL6hQvBPOvNbstnLLRLju7GfSCS9DRx GaB5igSuuMzhXmJD7ybUAWWvwjbDHIeANDhYUfoAUANJS3cbPldsf6V2C2PxNsM9AN02 cTHbYyYlTTrxvdydjQWBV03vvF099s5JnXhKFVIL8QSAA3ZfUr5csASBQb3MDMj0fvDL lIG7xK+Fm+WgF5TK8tGFepksgfSanVGB4/5O0377mC5zn7+6AdsTHswSBcpUhxW5CgkV v2bQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=pWztRfk0KM6ax3oD+E1yf8tb0/ZS2kY2fLFPdKSwh9g=; b=NFkUrao7mCRxBVjhJfgmwHhceF1Lpw2G56L87QeWRtl1iyZGt/qyk22DAPNJCWRaoa cYmIqWlIpbE7K6roZfAT5trXoSKj0MD1L1k0Xe8Je5XsoVkww607xdtr2RdUaULuJeta sPXoGW0JjEdAov0KvODRJtODQ4TCsclqfQcv2CPq3u0d7MvweIGXjPjmzNsarsbO7nxJ dPvCoI5FSLlEn2NztJxIQVMH1ZQwXI+PfmeWetnKvIn7dtWLEIP2qmpYVIf+gXNqF+Ow jA3gBKFdh3o6JevBJNtMt1YtaVldhKDW+/n0vWdRHQwyc5jVLkkzthBHlCBJGm+m7ysE C24Q== X-Gm-Message-State: AOUpUlHE5yiXTih3VKIzHLNKBKw5wYD8Irt60lx1x5WJTC9d480K/KlP Y0lLysUmtR8wYMXgQsvGSO8glrei X-Google-Smtp-Source: AAOMgpeYaoAMYYbQSimvcTdgJEdIQ39l362nZtvazKTWHDMC5ljfU/lhc2YwzuZSuZ0qHFBRaGdDj1Af X-Received: by 2002:a24:5fc8:: with SMTP id r191-v6mr2294922itb.38.1533252885771; Thu, 02 Aug 2018 16:34:45 -0700 (PDT) Date: Thu, 2 Aug 2018 23:34:37 +0000 In-Reply-To: <20180802233439.51643-1-posk@google.com> Message-Id: <20180802233439.51643-2-posk@google.com> Mime-Version: 1.0 References: <20180802233439.51643-1-posk@google.com> X-Mailer: git-send-email 2.18.0.597.ga71716f1ad-goog Subject: [PATCH v2 net-next 1/3] ip: discard IPv4 datagrams with overlapping segments. From: Peter Oskolkov To: David Miller , netdev@vger.kernel.org Cc: Eric Dumazet , Florian Westphal , Peter Oskolkov Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This behavior is required in IPv6, and there is little need to tolerate overlapping fragments in IPv4. This change simplifies the code and eliminates potential DDoS attack vectors. Tested: ran ip_defrag selftest (not yet available uptream). Suggested-by: David S. Miller Signed-off-by: Peter Oskolkov Signed-off-by: Eric Dumazet Cc: Florian Westphal Acked-by: Stephen Hemminger --- include/uapi/linux/snmp.h | 1 + net/ipv4/ip_fragment.c | 75 ++++++++++----------------------------- net/ipv4/proc.c | 1 + 3 files changed, 21 insertions(+), 56 deletions(-) diff --git a/include/uapi/linux/snmp.h b/include/uapi/linux/snmp.h index e5ebc83827ab..f80135e5feaa 100644 --- a/include/uapi/linux/snmp.h +++ b/include/uapi/linux/snmp.h @@ -56,6 +56,7 @@ enum IPSTATS_MIB_ECT1PKTS, /* InECT1Pkts */ IPSTATS_MIB_ECT0PKTS, /* InECT0Pkts */ IPSTATS_MIB_CEPKTS, /* InCEPkts */ + IPSTATS_MIB_REASM_OVERLAPS, /* ReasmOverlaps */ __IPSTATS_MIB_MAX }; diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index d14d741fb05e..960bf5eab59f 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -277,6 +277,7 @@ static int ip_frag_reinit(struct ipq *qp) /* Add new segment to existing queue. */ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) { + struct net *net = container_of(qp->q.net, struct net, ipv4.frags); struct sk_buff *prev, *next; struct net_device *dev; unsigned int fragsize; @@ -357,65 +358,23 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) } found: - /* We found where to put this one. Check for overlap with - * preceding fragment, and, if needed, align things so that - * any overlaps are eliminated. + /* RFC5722, Section 4, amended by Errata ID : 3089 + * When reassembling an IPv6 datagram, if + * one or more its constituent fragments is determined to be an + * overlapping fragment, the entire datagram (and any constituent + * fragments) MUST be silently discarded. + * + * We do the same here for IPv4. */ - if (prev) { - int i = (prev->ip_defrag_offset + prev->len) - offset; - if (i > 0) { - offset += i; - err = -EINVAL; - if (end <= offset) - goto err; - err = -ENOMEM; - if (!pskb_pull(skb, i)) - goto err; - if (skb->ip_summed != CHECKSUM_UNNECESSARY) - skb->ip_summed = CHECKSUM_NONE; - } - } + /* Is there an overlap with the previous fragment? */ + if (prev && + (prev->ip_defrag_offset + prev->len) > offset) + goto discard_qp; - err = -ENOMEM; - - while (next && next->ip_defrag_offset < end) { - int i = end - next->ip_defrag_offset; /* overlap is 'i' bytes */ - - if (i < next->len) { - int delta = -next->truesize; - - /* Eat head of the next overlapped fragment - * and leave the loop. The next ones cannot overlap. - */ - if (!pskb_pull(next, i)) - goto err; - delta += next->truesize; - if (delta) - add_frag_mem_limit(qp->q.net, delta); - next->ip_defrag_offset += i; - qp->q.meat -= i; - if (next->ip_summed != CHECKSUM_UNNECESSARY) - next->ip_summed = CHECKSUM_NONE; - break; - } else { - struct sk_buff *free_it = next; - - /* Old fragment is completely overridden with - * new one drop it. - */ - next = next->next; - - if (prev) - prev->next = next; - else - qp->q.fragments = next; - - qp->q.meat -= free_it->len; - sub_frag_mem_limit(qp->q.net, free_it->truesize); - kfree_skb(free_it); - } - } + /* Is there an overlap with the next fragment? */ + if (next && next->ip_defrag_offset < end) + goto discard_qp; /* Note : skb->ip_defrag_offset and skb->dev share the same location */ dev = skb->dev; @@ -463,6 +422,10 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) skb_dst_drop(skb); return -EINPROGRESS; +discard_qp: + inet_frag_kill(&qp->q); + err = -EINVAL; + __IP_INC_STATS(net, IPSTATS_MIB_REASM_OVERLAPS); err: kfree_skb(skb); return err; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index b46e4cf9a55a..70289682a670 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -119,6 +119,7 @@ static const struct snmp_mib snmp4_ipextstats_list[] = { SNMP_MIB_ITEM("InECT1Pkts", IPSTATS_MIB_ECT1PKTS), SNMP_MIB_ITEM("InECT0Pkts", IPSTATS_MIB_ECT0PKTS), SNMP_MIB_ITEM("InCEPkts", IPSTATS_MIB_CEPKTS), + SNMP_MIB_ITEM("ReasmOverlaps", IPSTATS_MIB_REASM_OVERLAPS), SNMP_MIB_SENTINEL };