Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp37349imu; Thu, 8 Nov 2018 14:19:41 -0800 (PST) X-Google-Smtp-Source: AJdET5d3SManBXl4KBZjsHOw6n5SssN5JRusJtkcCThJ6Jugk4r7CWaJQWo+wcHuVPTh5w+XWip2 X-Received: by 2002:a62:76c9:: with SMTP id r192-v6mr6342056pfc.17.1541715581796; Thu, 08 Nov 2018 14:19:41 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1541715581; cv=none; d=google.com; s=arc-20160816; b=aLbg4M6JGeiR+csR/bNcpGyI1Jf5AVAiPdbb+oE6sG7G8WrWHlC9UEppfF1gx1u2gQ w9ME2P6JLdunL1WMdR1cGRtXWvb6kv/7K5I0jmwlytgG4DCI5QIGI/Ht/3pFn62QUNdq kj2roroiPosHpNOib7O8atSu6Fw3l3OmlEw2RbXcPgh0S297UENWiCPb7bBqNHVXVXP2 uF/hIx3A2GmSqYbbzmAw9sZPLvHghbRJ72FvYI5UEr11dv4doo+V4x9iNs92+FMfZGHc 5PgVbK3u9hPSKoJxoPBy5dxfOVkSZQ6eWcI4WxBqSqdns6+KSNoiS/koA2BYsY4S+lQ/ 1ZFQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=wvpGlMrJR6nXTUk1/sl38WXf8Og/eKOJthZ9WCSe4YM=; b=cOKPDOYPGHzubVLBMzoejVcGfUkT7Hrg1DP0yBnARglALc5QF70/MYA07yjovNqXmf hHWkSjJRz4Tj1qW9GC3xaqDYGDGBUJjGDd3XakRvW4HclP4qPYLZIEBio7z+2vJ2jBt7 wJT6cVkrM5YZUBT6cDs190gMNo0DrAJmQAXvibrtPYTQgJNo1yHZd6fdolZI1pda86wB ktrbT4egZW2DldbrGPL390XN/Ci9OANJQp8OsBEs4RkTvdmnq1t3H4lW32Fm6mH4ve1I KmWVAx/GbRTNWCLbK703vP8QsI+tlf8msuwkoPPTSwBgqUTVNMIED+sQ6ZU3JN4tZrE4 b+gA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=MhTJUmRt; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l36-v6si5783218plg.289.2018.11.08.14.19.26; Thu, 08 Nov 2018 14:19:41 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=MhTJUmRt; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732144AbeKIHob (ORCPT + 99 others); Fri, 9 Nov 2018 02:44:31 -0500 Received: from mail.kernel.org ([198.145.29.99]:37320 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730843AbeKIHo3 (ORCPT ); Fri, 9 Nov 2018 02:44:29 -0500 Received: from localhost (unknown [208.72.13.198]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 907CF208A3; Thu, 8 Nov 2018 22:06:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1541714817; bh=BGRUwpaTkapS3aSGnMbAVZ0HBX23gH4RTryQC02F0Q4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MhTJUmRtqTNr0e4RnLko3+bpaTxX7JTHXoI6qYP5Iymd7/3qs6Y+hJkhBb4vm9fIq 7hN+jQwe+Yj2bwyQuWfL5ibznwOkjD4wF3HMNvP6abczXBy7WlEUU4lt4dqh+WuVJj aPd2fcfUCAdem7JGGJOBioMfzXtr4SU0pVl9Wirw= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Sam Kumar , Eric Dumazet , Sean Tranchetti , "David S. Miller" Subject: [PATCH 4.9 143/171] net: udp: fix handling of CHECKSUM_COMPLETE packets Date: Thu, 8 Nov 2018 13:51:53 -0800 Message-Id: <20181108215137.317545751@linuxfoundation.org> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181108215127.257643509@linuxfoundation.org> References: <20181108215127.257643509@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.9-stable review patch. If anyone has any objections, please let me know. ------------------ From: Sean Tranchetti [ Upstream commit db4f1be3ca9b0ef7330763d07bf4ace83ad6f913 ] Current handling of CHECKSUM_COMPLETE packets by the UDP stack is incorrect for any packet that has an incorrect checksum value. udp4/6_csum_init() will both make a call to __skb_checksum_validate_complete() to initialize/validate the csum field when receiving a CHECKSUM_COMPLETE packet. When this packet fails validation, skb->csum will be overwritten with the pseudoheader checksum so the packet can be fully validated by software, but the skb->ip_summed value will be left as CHECKSUM_COMPLETE so that way the stack can later warn the user about their hardware spewing bad checksums. Unfortunately, leaving the SKB in this state can cause problems later on in the checksum calculation. Since the the packet is still marked as CHECKSUM_COMPLETE, udp_csum_pull_header() will SUBTRACT the checksum of the UDP header from skb->csum instead of adding it, leaving us with a garbage value in that field. Once we try to copy the packet to userspace in the udp4/6_recvmsg(), we'll make a call to skb_copy_and_csum_datagram_msg() to checksum the packet data and add it in the garbage skb->csum value to perform our final validation check. Since the value we're validating is not the proper checksum, it's possible that the folded value could come out to 0, causing us not to drop the packet. Instead, we believe that the packet was checksummed incorrectly by hardware since skb->ip_summed is still CHECKSUM_COMPLETE, and we attempt to warn the user with netdev_rx_csum_fault(skb->dev); Unfortunately, since this is the UDP path, skb->dev has been overwritten by skb->dev_scratch and is no longer a valid pointer, so we end up reading invalid memory. This patch addresses this problem in two ways: 1) Do not use the dev pointer when calling netdev_rx_csum_fault() from skb_copy_and_csum_datagram_msg(). Since this gets called from the UDP path where skb->dev has been overwritten, we have no way of knowing if the pointer is still valid. Also for the sake of consistency with the other uses of netdev_rx_csum_fault(), don't attempt to call it if the packet was checksummed by software. 2) Add better CHECKSUM_COMPLETE handling to udp4/6_csum_init(). If we receive a packet that's CHECKSUM_COMPLETE that fails verification (i.e. skb->csum_valid == 0), check who performed the calculation. It's possible that the checksum was done in software by the network stack earlier (such as Netfilter's CONNTRACK module), and if that says the checksum is bad, we can drop the packet immediately instead of waiting until we try and copy it to userspace. Otherwise, we need to mark the SKB as CHECKSUM_NONE, since the skb->csum field no longer contains the full packet checksum after the call to __skb_checksum_validate_complete(). Fixes: e6afc8ace6dd ("udp: remove headers from UDP packets before queueing") Fixes: c84d949057ca ("udp: copy skb->truesize in the first cache line") Cc: Sam Kumar Cc: Eric Dumazet Signed-off-by: Sean Tranchetti Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/datagram.c | 5 +++-- net/ipv4/udp.c | 20 ++++++++++++++++++-- net/ipv6/ip6_checksum.c | 20 ++++++++++++++++++-- 3 files changed, 39 insertions(+), 6 deletions(-) --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -754,8 +754,9 @@ int skb_copy_and_csum_datagram_msg(struc return -EINVAL; } - if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) - netdev_rx_csum_fault(skb->dev); + if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && + !skb->csum_complete_sw) + netdev_rx_csum_fault(NULL); } return 0; fault: --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1726,8 +1726,24 @@ static inline int udp4_csum_init(struct /* Note, we are only interested in != 0 or == 0, thus the * force to int. */ - return (__force int)skb_checksum_init_zero_check(skb, proto, uh->check, - inet_compute_pseudo); + err = (__force int)skb_checksum_init_zero_check(skb, proto, uh->check, + inet_compute_pseudo); + if (err) + return err; + + if (skb->ip_summed == CHECKSUM_COMPLETE && !skb->csum_valid) { + /* If SW calculated the value, we know it's bad */ + if (skb->csum_complete_sw) + return 1; + + /* HW says the value is bad. Let's validate that. + * skb->csum is no longer the full packet checksum, + * so don't treat it as such. + */ + skb_checksum_complete_unset(skb); + } + + return 0; } /* wrapper for udp_queue_rcv_skb tacking care of csum conversion and --- a/net/ipv6/ip6_checksum.c +++ b/net/ipv6/ip6_checksum.c @@ -87,8 +87,24 @@ int udp6_csum_init(struct sk_buff *skb, * Note, we are only interested in != 0 or == 0, thus the * force to int. */ - return (__force int)skb_checksum_init_zero_check(skb, proto, uh->check, - ip6_compute_pseudo); + err = (__force int)skb_checksum_init_zero_check(skb, proto, uh->check, + ip6_compute_pseudo); + if (err) + return err; + + if (skb->ip_summed == CHECKSUM_COMPLETE && !skb->csum_valid) { + /* If SW calculated the value, we know it's bad */ + if (skb->csum_complete_sw) + return 1; + + /* HW says the value is bad. Let's validate that. + * skb->csum is no longer the full packet checksum, + * so don't treat is as such. + */ + skb_checksum_complete_unset(skb); + } + + return 0; } EXPORT_SYMBOL(udp6_csum_init);