From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.0 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 99DE7C43381 for ; Thu, 14 Feb 2019 10:31:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5FD8A2229F for ; Thu, 14 Feb 2019 10:31:25 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="nRLj1oJt" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2393201AbfBNKbZ (ORCPT ); Thu, 14 Feb 2019 05:31:25 -0500 Received: from mail-ed1-f42.google.com ([209.85.208.42]:38565 "EHLO mail-ed1-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2392080AbfBNKbY (ORCPT ); Thu, 14 Feb 2019 05:31:24 -0500 Received: by mail-ed1-f42.google.com with SMTP id h58so4572272edb.5 for ; Thu, 14 Feb 2019 02:31:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=7/ORFHsQ58yDA9mdVZmp4tiH9FnJRdUHRTNTXnGNpFY=; b=nRLj1oJt7Ju+WYGojrpkfXzVmK/vWDBcqDm9SAkbqau+Vuz4G8o7IpAQt3392ax8yg GSI2DHpFPwv0GgNcFQbqiHp9JE9LHN6wdNcDSPeGEyR+uHrtO89EYgl4ONdb1DFvUn0A QieOxmvMCQKOXFHlBNx8NEz0hv6gF5IXh30CAZm9SWZa+uqwYeJCg5DXxydpEvc3yFtW Aia290q4yFVauTbo7tZYFkdD42Sw7yDaXB+0kB/tBQXHUk7nlAsjlofXI7Whh7SbUQeF Jx2lh0ySYSK5V4rvhCJYuuG0FuIg2UuIDY9CILTSZuHHRiGP+2Jy0OZXgrhqUK987eVQ pKQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=7/ORFHsQ58yDA9mdVZmp4tiH9FnJRdUHRTNTXnGNpFY=; b=HCGCIITVzGRBsTrUIu+tPqHNxZ2YDOWpwy+GLanpeMuzqZP3uL20awV+HaA4xd58FU xSjjAZXWkGh1MGSmCG5A1JhM8eFBA4B4S3QYVGB4fuz6l8fk+Ib0dY7I1QwG6jzCfdzI 39afZqBFmWHb/wUDgYHgBHLAANQfa/VdnRekwHfsUEmAja5CsSnS6cG6sMM8ujsNyxPq nxFLsBtIfVCd0may9ZOPy/R3A24DNixzwHaJNUDguLnldCRcqbpKVV+zGIJfIYtsbdIm b9CyMT5uKiyplJkfO5Mrjn2u6XPLPdXbru9Mq4Q0YoqSCMV2qnzpz710LBzbsicn1mD5 dTvw== X-Gm-Message-State: AHQUAuakWkuvyHQmyvhfEfhoA7fqD2ssbEB+Ng8cLM5FqmuG7AQgCOEQ h8VT/kRk31FJz+rKrnp2jKEqefF5dr4= X-Google-Smtp-Source: AHgI3IapcQe93CqUxb9pLRdNGi/8KixueiGRDAgVBuKXDEJxrIXR0n4Pf/ghv09JdWW5O9U8YnK1FA== X-Received: by 2002:a17:906:354a:: with SMTP id s10mr2265133eja.21.1550140282340; Thu, 14 Feb 2019 02:31:22 -0800 (PST) Received: from jwang-pc.pb.local ([2001:1438:4010:254c:1e6f:65ff:fed4:d10]) by smtp.gmail.com with ESMTPSA id p30sm543052edd.85.2019.02.14.02.31.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 14 Feb 2019 02:31:21 -0800 (PST) From: Jack Wang To: gregkh@linuxfoundation.org, stable@vger.kernel.org Cc: Daniel Axtens , "David S . Miller" , Jack Wang Subject: [stable-4.9 && 4.14 1/2] net: create skb_gso_validate_mac_len() Date: Thu, 14 Feb 2019 11:31:17 +0100 Message-Id: <20190214103118.4350-2-jinpuwang@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190214103118.4350-1-jinpuwang@gmail.com> References: <20190214103118.4350-1-jinpuwang@gmail.com> Sender: stable-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org From: Daniel Axtens commit 2b16f048729bf35e6c28a40cbfad07239f9dcd90 upstream If you take a GSO skb, and split it into packets, will the MAC length (L2 + L3 + L4 headers + payload) of those packets be small enough to fit within a given length? Move skb_gso_mac_seglen() to skbuff.h with other related functions like skb_gso_network_seglen() so we can use it, and then create skb_gso_validate_mac_len to do the full calculation. Signed-off-by: Daniel Axtens Signed-off-by: David S. Miller [jwang: cherry pick for CVE-2018-1000026] Signed-off-by: Jack Wang --- include/linux/skbuff.h | 16 +++++++++++ net/core/skbuff.c | 63 +++++++++++++++++++++++++++++++++--------- net/sched/sch_tbf.c | 10 ------- 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 39c2570ddcf6..50a4a5968f3a 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3317,6 +3317,7 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen); void skb_scrub_packet(struct sk_buff *skb, bool xnet); unsigned int skb_gso_transport_seglen(const struct sk_buff *skb); bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu); +bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len); struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); struct sk_buff *skb_vlan_untag(struct sk_buff *skb); int skb_ensure_writable(struct sk_buff *skb, int write_len); @@ -4087,6 +4088,21 @@ static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb) return hdr_len + skb_gso_transport_seglen(skb); } +/** + * skb_gso_mac_seglen - Return length of individual segments of a gso packet + * + * @skb: GSO skb + * + * skb_gso_mac_seglen is used to determine the real size of the + * individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4 + * headers (TCP/UDP). + */ +static inline unsigned int skb_gso_mac_seglen(const struct sk_buff *skb) +{ + unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb); + return hdr_len + skb_gso_transport_seglen(skb); +} + /* Local Checksum Offload. * Compute outer checksum based on the assumption that the * inner checksum will be offloaded later. diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 873032d1a083..6dbd2c54b2c9 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4930,37 +4930,74 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); /** - * skb_gso_validate_mtu - Return in case such skb fits a given MTU + * skb_gso_size_check - check the skb size, considering GSO_BY_FRAGS * - * @skb: GSO skb - * @mtu: MTU to validate against + * There are a couple of instances where we have a GSO skb, and we + * want to determine what size it would be after it is segmented. * - * skb_gso_validate_mtu validates if a given skb will fit a wanted MTU - * once split. + * We might want to check: + * - L3+L4+payload size (e.g. IP forwarding) + * - L2+L3+L4+payload size (e.g. sanity check before passing to driver) + * + * This is a helper to do that correctly considering GSO_BY_FRAGS. + * + * @seg_len: The segmented length (from skb_gso_*_seglen). In the + * GSO_BY_FRAGS case this will be [header sizes + GSO_BY_FRAGS]. + * + * @max_len: The maximum permissible length. + * + * Returns true if the segmented length <= max length. */ -bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu) -{ +static inline bool skb_gso_size_check(const struct sk_buff *skb, + unsigned int seg_len, + unsigned int max_len) { const struct skb_shared_info *shinfo = skb_shinfo(skb); const struct sk_buff *iter; - unsigned int hlen; - - hlen = skb_gso_network_seglen(skb); if (shinfo->gso_size != GSO_BY_FRAGS) - return hlen <= mtu; + return seg_len <= max_len; /* Undo this so we can re-use header sizes */ - hlen -= GSO_BY_FRAGS; + seg_len -= GSO_BY_FRAGS; skb_walk_frags(skb, iter) { - if (hlen + skb_headlen(iter) > mtu) + if (seg_len + skb_headlen(iter) > max_len) return false; } return true; } + +/** + * skb_gso_validate_mtu - Return in case such skb fits a given MTU + * + * @skb: GSO skb + * @mtu: MTU to validate against + * + * skb_gso_validate_mtu validates if a given skb will fit a wanted MTU + * once split. + */ +bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu) +{ + return skb_gso_size_check(skb, skb_gso_network_seglen(skb), mtu); +} EXPORT_SYMBOL_GPL(skb_gso_validate_mtu); +/** + * skb_gso_validate_mac_len - Will a split GSO skb fit in a given length? + * + * @skb: GSO skb + * @len: length to validate against + * + * skb_gso_validate_mac_len validates if a given skb will fit a wanted + * length once split, including L2, L3 and L4 headers and the payload. + */ +bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len) +{ + return skb_gso_size_check(skb, skb_gso_mac_seglen(skb), len); +} +EXPORT_SYMBOL_GPL(skb_gso_validate_mac_len); + static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb) { int mac_len; diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index b36ecb58aa6e..107cc76b6e24 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -142,16 +142,6 @@ static u64 psched_ns_t2l(const struct psched_ratecfg *r, return len; } -/* - * Return length of individual segments of a gso packet, - * including all headers (MAC, IP, TCP/UDP) - */ -static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb) -{ - unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb); - return hdr_len + skb_gso_transport_seglen(skb); -} - /* GSO packet is too big, segment it so that tbf can transmit * each segment in time */ -- 2.17.1