Received: by 2002:ac0:aed5:0:0:0:0:0 with SMTP id t21csp5897301imb; Fri, 8 Mar 2019 05:01:58 -0800 (PST) X-Google-Smtp-Source: APXvYqw8OX5M5TLwGc1O2XOczxfYkdzQVaGLiOhjBE5D/WaKWahbJQZkxwFlXYAUl2jyG7Qo6PIM X-Received: by 2002:a17:902:d88c:: with SMTP id b12mr18895365plz.339.1552050118437; Fri, 08 Mar 2019 05:01:58 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1552050118; cv=none; d=google.com; s=arc-20160816; b=uUy19qpccrRX6fxUxE5GqVgREQeBD/7KdmtF3XKG9fE3e2vbPdpM4i73VO4ZR7WCRd Xhi3x4cVLonfw7P/le7nT1u1cef3YPGLOLqtLptLa59sWtdmaX+zDSWCB2hdWwfc/sIy f+Z/sHPo7IuUKB2+uLSVqjvsFwgxFfjsL+Vp298AfDE5Hj/Sdo/GHG0LtlGbg9JUUH+t y5Ny58t9nrcz54kF87DGbsBZaxcqSPC5tvkQjm0u8AC9IDxSdEsGkPbZdY4qGKXsjmcM i25EMbhNnWVayGwv4RMqd19ToyJMtwFtvF5lMCyJ2pUflq/LiCwmUePSAXKeDIl1lW2b MfuQ== 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=1M32wG7zsbjoCBZkRb+vtDJ/lyFs5yw2v3mfT/d7kng=; b=dHfVeqJ+up40BcVVPkxa2YZJk/X35rRg7S/TjYr/qZCect8mhaN+S9l80/FgGxoOVw Jh9WB88jEDDMgTekG4izi9fYTI2otXJr9klbYTC/3q5nxfyYjUlzolxGPWAqFuoNW95G 7B4eC0QD1Q2bbONYFyhr7JD+Tf3Mmw4B6OyMAhmIRUgZ0r7QaV2KG0XURJYuEye5b4pu Vr2ktn2YLgk7oXvetIjxYbs01VSuFvGS/nX7XABU8/Woh0RQimnaT0wLFtWCthd/7C65 JZhbhWombzBd9tKMkaEYsHFVe3yE4BdT6eXXZuUbXiazY3CYuxuQvKQnRGTxWjcaIF4x D32g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=DQjz1cwN; 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 l70si6593003pgd.470.2019.03.08.05.01.40; Fri, 08 Mar 2019 05:01:58 -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=DQjz1cwN; 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 S1728169AbfCHM7c (ORCPT + 99 others); Fri, 8 Mar 2019 07:59:32 -0500 Received: from mail.kernel.org ([198.145.29.99]:36014 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728125AbfCHM70 (ORCPT ); Fri, 8 Mar 2019 07:59:26 -0500 Received: from localhost (5356596B.cm-6-7b.dynamic.ziggo.nl [83.86.89.107]) (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 3754C20661; Fri, 8 Mar 2019 12:59:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1552049964; bh=90SyjeInWFLiTL54p8M1kr6G+whltohSw2tbSJ+6UTE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DQjz1cwNFvjXipmw3EsLrFfUSh9LvtHH0L4aBQBSA7XnCXHftFKt/VIsj1aupKbTN 5xW0sbOJ7bGS0cGzakNmp8uDW3bjOCKjxNPT4e1b4DTSVcDMiYIuA/hgH7leRH94Qq Uu5G5MMm0eylsNSI2/8rrxBVI1GlUO/umU9kCsnM= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Gao Xiang , Chao Yu Subject: [PATCH 4.19 07/68] staging: erofs: compressed_pages should not be accessed again after freed Date: Fri, 8 Mar 2019 13:49:37 +0100 Message-Id: <20190308124911.137534105@linuxfoundation.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190308124910.696595153@linuxfoundation.org> References: <20190308124910.696595153@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review X-Patchwork-Hint: ignore 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.19-stable review patch. If anyone has any objections, please let me know. ------------------ From: Gao Xiang commit af692e117cb8cd9d3d844d413095775abc1217f9 upstream. This patch resolves the following page use-after-free issue, z_erofs_vle_unzip: ... for (i = 0; i < nr_pages; ++i) { ... z_erofs_onlinepage_endio(page); (1) } for (i = 0; i < clusterpages; ++i) { page = compressed_pages[i]; if (page->mapping == mngda) (2) continue; /* recycle all individual staging pages */ (void)z_erofs_gather_if_stagingpage(page_pool, page); (3) WRITE_ONCE(compressed_pages[i], NULL); } ... After (1) is executed, page is freed and could be then reused, if compressed_pages is scanned after that, it could fall info (2) or (3) by mistake and that could finally be in a mess. This patch aims to solve the above issue only with little changes as much as possible in order to make the fix backport easier. Fixes: 3883a79abd02 ("staging: erofs: introduce VLE decompression support") Cc: # 4.19+ Signed-off-by: Gao Xiang Reviewed-by: Chao Yu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/erofs/unzip_vle.c | 38 +++++++++++++++++----------------- drivers/staging/erofs/unzip_vle.h | 3 -- drivers/staging/erofs/unzip_vle_lz4.c | 20 ++++++++--------- 3 files changed, 30 insertions(+), 31 deletions(-) --- a/drivers/staging/erofs/unzip_vle.c +++ b/drivers/staging/erofs/unzip_vle.c @@ -925,11 +925,10 @@ repeat: if (llen > grp->llen) llen = grp->llen; - err = z_erofs_vle_unzip_fast_percpu(compressed_pages, - clusterpages, pages, llen, work->pageofs, - z_erofs_onlinepage_endio); + err = z_erofs_vle_unzip_fast_percpu(compressed_pages, clusterpages, + pages, llen, work->pageofs); if (err != -ENOTSUPP) - goto out_percpu; + goto out; if (sparsemem_pages >= nr_pages) goto skip_allocpage; @@ -950,8 +949,25 @@ skip_allocpage: erofs_vunmap(vout, nr_pages); out: + /* must handle all compressed pages before endding pages */ + for (i = 0; i < clusterpages; ++i) { + page = compressed_pages[i]; + +#ifdef EROFS_FS_HAS_MANAGED_CACHE + if (page->mapping == mngda) + continue; +#endif + /* recycle all individual staging pages */ + (void)z_erofs_gather_if_stagingpage(page_pool, page); + + WRITE_ONCE(compressed_pages[i], NULL); + } + for (i = 0; i < nr_pages; ++i) { page = pages[i]; + if (!page) + continue; + DBG_BUGON(page->mapping == NULL); /* recycle all individual staging pages */ @@ -964,20 +980,6 @@ out: z_erofs_onlinepage_endio(page); } -out_percpu: - for (i = 0; i < clusterpages; ++i) { - page = compressed_pages[i]; - -#ifdef EROFS_FS_HAS_MANAGED_CACHE - if (page->mapping == mngda) - continue; -#endif - /* recycle all individual staging pages */ - (void)z_erofs_gather_if_stagingpage(page_pool, page); - - WRITE_ONCE(compressed_pages[i], NULL); - } - if (pages == z_pagemap_global) mutex_unlock(&z_pagemap_global_lock); else if (unlikely(pages != pages_onstack)) --- a/drivers/staging/erofs/unzip_vle.h +++ b/drivers/staging/erofs/unzip_vle.h @@ -218,8 +218,7 @@ extern int z_erofs_vle_plain_copy(struct extern int z_erofs_vle_unzip_fast_percpu(struct page **compressed_pages, unsigned clusterpages, struct page **pages, - unsigned outlen, unsigned short pageofs, - void (*endio)(struct page *)); + unsigned int outlen, unsigned short pageofs); extern int z_erofs_vle_unzip_vmap(struct page **compressed_pages, unsigned clusterpages, void *vaddr, unsigned llen, --- a/drivers/staging/erofs/unzip_vle_lz4.c +++ b/drivers/staging/erofs/unzip_vle_lz4.c @@ -105,8 +105,7 @@ int z_erofs_vle_unzip_fast_percpu(struct unsigned clusterpages, struct page **pages, unsigned outlen, - unsigned short pageofs, - void (*endio)(struct page *)) + unsigned short pageofs) { void *vin, *vout; unsigned nr_pages, i, j; @@ -128,31 +127,30 @@ int z_erofs_vle_unzip_fast_percpu(struct ret = z_erofs_unzip_lz4(vin, vout + pageofs, clusterpages * PAGE_SIZE, outlen); - if (ret >= 0) { - outlen = ret; - ret = 0; - } + if (ret < 0) + goto out; + ret = 0; for (i = 0; i < nr_pages; ++i) { j = min((unsigned)PAGE_SIZE - pageofs, outlen); if (pages[i] != NULL) { - if (ret < 0) - SetPageError(pages[i]); - else if (clusterpages == 1 && pages[i] == compressed_pages[0]) + if (clusterpages == 1 && + pages[i] == compressed_pages[0]) { memcpy(vin + pageofs, vout + pageofs, j); - else { + } else { void *dst = kmap_atomic(pages[i]); memcpy(dst + pageofs, vout + pageofs, j); kunmap_atomic(dst); } - endio(pages[i]); } vout += PAGE_SIZE; outlen -= j; pageofs = 0; } + +out: preempt_enable(); if (clusterpages == 1)