Received: by 10.192.165.156 with SMTP id m28csp1115289imm; Wed, 11 Apr 2018 12:43:14 -0700 (PDT) X-Google-Smtp-Source: AIpwx490+CnPDpQTFJRUUhBFYBAYXLjTuQFLclKA637eXDxvzDfs9FTasMBNKAJiFEdtxCOSqWRo X-Received: by 2002:a17:902:71cc:: with SMTP id t12-v6mr6335402plm.247.1523475794462; Wed, 11 Apr 2018 12:43:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523475794; cv=none; d=google.com; s=arc-20160816; b=j8F70sJy9iqQauylefRTU7KjliOgOhv3Ud4kXH+WGyx3T4SxKCVUmHo1NKi9QRaNuu yvOdZtekuKKVlh6Hy4d9QN0pQm2WGvPBewhrmSRQIYwcZEHV826cpRFKtnHCahMaxuB+ mvjdoBJ6aeut41+uoGe+a0kCPsf0SwHEz0ZQnlxwPkSG+j0JbfFDiA9/kvtMVoi6KHpc 8QeVwwIY2hGn5NA0zi+E/kTkxf22DAd8CYIiEDdwSHcOT5tlK6EGEIKcCA5P47KGKVnU ri9Jq3n/6ej7oRnv+bYY50SZ+hpT5vPzQBwrP30j1VJI9I6ABqJCjTuMoyq9+b+1Ajd9 LuGw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=yo1TKBr215CWtfvSdfAw0O+ydtYtNPJlqWWdboDjJs8=; b=PNxWoE5nfVNi5egt+WWRqxbPPl4d4GPOzK0VJ8IITHrhEixzVNubMNXTEZ9nlwRoZe E6DgsQJnsAvKV84a5gu2P10PfhjeEswV2OwILDTAcoolhhbS2eqSN005wryc18VEUcAQ QZ44RYPVTi/rd1Cr5JXYOKkTNJvapVaReMJ1/cfrkFK9UYpDHmRHol63puVFsC2FSU1B Yf7y6F5/yGtBjXBP41i0K1PztKYSFvdqiaVSQh7u/9uVh06bUrzw/bb6IoEIs8QFEbER gtyCFMSnm/EG0RxsXh2FwEBjgWLMAwL6hrE1xN+nbyCeVR8p0Oqx8oy60fCcx+DxeATz yoQw== ARC-Authentication-Results: i=1; mx.google.com; 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 u20si1077069pgv.12.2018.04.11.12.42.37; Wed, 11 Apr 2018 12:43:14 -0700 (PDT) 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; 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 S934228AbeDKTBV (ORCPT + 99 others); Wed, 11 Apr 2018 15:01:21 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:38110 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932906AbeDKTBS (ORCPT ); Wed, 11 Apr 2018 15:01:18 -0400 Received: from localhost (LFbn-1-12247-202.w90-92.abo.wanadoo.fr [90.92.61.202]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id 3E63ADAC; Wed, 11 Apr 2018 19:01:17 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, "Jason A. Donenfeld" , Steffen Klassert , Herbert Xu , "David S. Miller" , David Howells , Sabrina Dubroca , "Michael S. Tsirkin" , Jason Wang , Sasha Levin Subject: [PATCH 4.9 190/310] skbuff: return -EMSGSIZE in skb_to_sgvec to prevent overflow Date: Wed, 11 Apr 2018 20:35:29 +0200 Message-Id: <20180411183630.777163220@linuxfoundation.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180411183622.305902791@linuxfoundation.org> References: <20180411183622.305902791@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 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: "Jason A. Donenfeld" [ Upstream commit 48a1df65334b74bd7531f932cca5928932abf769 ] This is a defense-in-depth measure in response to bugs like 4d6fa57b4dab ("macsec: avoid heap overflow in skb_to_sgvec"). There's not only a potential overflow of sglist items, but also a stack overflow potential, so we fix this by limiting the amount of recursion this function is allowed to do. Not actually providing a bounded base case is a future disaster that we can easily avoid here. As a small matter of house keeping, we take this opportunity to move the documentation comment over the actual function the documentation is for. While this could be implemented by using an explicit stack of skbuffs, when implementing this, the function complexity increased considerably, and I don't think such complexity and bloat is actually worth it. So, instead I built this and tested it on x86, x86_64, ARM, ARM64, and MIPS, and measured the stack usage there. I also reverted the recent MIPS changes that give it a separate IRQ stack, so that I could experience some worst-case situations. I found that limiting it to 24 layers deep yielded a good stack usage with room for safety, as well as being much deeper than any driver actually ever creates. Signed-off-by: Jason A. Donenfeld Cc: Steffen Klassert Cc: Herbert Xu Cc: "David S. Miller" Cc: David Howells Cc: Sabrina Dubroca Cc: "Michael S. Tsirkin" Cc: Jason Wang Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/skbuff.h | 8 +++--- net/core/skbuff.c | 65 +++++++++++++++++++++++++++++++------------------ 2 files changed, 46 insertions(+), 27 deletions(-) --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -984,10 +984,10 @@ struct sk_buff *skb_realloc_headroom(str unsigned int headroom); struct sk_buff *skb_copy_expand(const struct sk_buff *skb, int newheadroom, int newtailroom, gfp_t priority); -int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg, - int offset, int len); -int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, - int len); +int __must_check skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg, + int offset, int len); +int __must_check skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, + int offset, int len); int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer); int skb_pad(struct sk_buff *skb, int pad); #define dev_kfree_skb(a) consume_skb(a) --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3475,24 +3475,18 @@ void __init skb_init(void) NULL); } -/** - * skb_to_sgvec - Fill a scatter-gather list from a socket buffer - * @skb: Socket buffer containing the buffers to be mapped - * @sg: The scatter-gather list to map into - * @offset: The offset into the buffer's contents to start mapping - * @len: Length of buffer space to be mapped - * - * Fill the specified scatter-gather list with mappings/pointers into a - * region of the buffer space attached to a socket buffer. - */ static int -__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) +__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len, + unsigned int recursion_level) { int start = skb_headlen(skb); int i, copy = start - offset; struct sk_buff *frag_iter; int elt = 0; + if (unlikely(recursion_level >= 24)) + return -EMSGSIZE; + if (copy > 0) { if (copy > len) copy = len; @@ -3511,6 +3505,8 @@ __skb_to_sgvec(struct sk_buff *skb, stru end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]); if ((copy = end - offset) > 0) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + if (unlikely(elt && sg_is_last(&sg[elt - 1]))) + return -EMSGSIZE; if (copy > len) copy = len; @@ -3525,16 +3521,22 @@ __skb_to_sgvec(struct sk_buff *skb, stru } skb_walk_frags(skb, frag_iter) { - int end; + int end, ret; WARN_ON(start > offset + len); end = start + frag_iter->len; if ((copy = end - offset) > 0) { + if (unlikely(elt && sg_is_last(&sg[elt - 1]))) + return -EMSGSIZE; + if (copy > len) copy = len; - elt += __skb_to_sgvec(frag_iter, sg+elt, offset - start, - copy); + ret = __skb_to_sgvec(frag_iter, sg+elt, offset - start, + copy, recursion_level + 1); + if (unlikely(ret < 0)) + return ret; + elt += ret; if ((len -= copy) == 0) return elt; offset += copy; @@ -3545,6 +3547,31 @@ __skb_to_sgvec(struct sk_buff *skb, stru return elt; } +/** + * skb_to_sgvec - Fill a scatter-gather list from a socket buffer + * @skb: Socket buffer containing the buffers to be mapped + * @sg: The scatter-gather list to map into + * @offset: The offset into the buffer's contents to start mapping + * @len: Length of buffer space to be mapped + * + * Fill the specified scatter-gather list with mappings/pointers into a + * region of the buffer space attached to a socket buffer. Returns either + * the number of scatterlist items used, or -EMSGSIZE if the contents + * could not fit. + */ +int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) +{ + int nsg = __skb_to_sgvec(skb, sg, offset, len, 0); + + if (nsg <= 0) + return nsg; + + sg_mark_end(&sg[nsg - 1]); + + return nsg; +} +EXPORT_SYMBOL_GPL(skb_to_sgvec); + /* As compared with skb_to_sgvec, skb_to_sgvec_nomark only map skb to given * sglist without mark the sg which contain last skb data as the end. * So the caller can mannipulate sg list as will when padding new data after @@ -3567,19 +3594,11 @@ __skb_to_sgvec(struct sk_buff *skb, stru int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) { - return __skb_to_sgvec(skb, sg, offset, len); + return __skb_to_sgvec(skb, sg, offset, len, 0); } EXPORT_SYMBOL_GPL(skb_to_sgvec_nomark); -int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) -{ - int nsg = __skb_to_sgvec(skb, sg, offset, len); - sg_mark_end(&sg[nsg - 1]); - - return nsg; -} -EXPORT_SYMBOL_GPL(skb_to_sgvec); /** * skb_cow_data - Check that a socket buffer's data buffers are writable