From patchwork Fri Sep 29 10:29:55 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Will Deacon X-Patchwork-Id: 114505 Delivered-To: patch@linaro.org Received: by 10.140.104.133 with SMTP id a5csp626589qgf; Fri, 29 Sep 2017 03:29:43 -0700 (PDT) X-Google-Smtp-Source: AOwi7QBwEtL0UkVVcCdtsSyFzllqYsfx/QoMWWnpNVUurbFI84MOqwN3K0kulP9ihjtORlgZU6PY X-Received: by 10.99.114.17 with SMTP id n17mr6936824pgc.43.1506680983248; Fri, 29 Sep 2017 03:29:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1506680983; cv=none; d=google.com; s=arc-20160816; b=bwO8u1fXK2vHhPqxcf4XxlojrsU1fCNFp7BZC8TmyjqaAjFtdJkTAM55YA07hnuU0R jkL0RjK+K+e3t4LUDp4bHZhlv64Y04AY6e21QcoRtz/AzI+5wb+wJ//Wa4CjtWaDxWwp wjQKsuTk/JIIpI7MPFgVBbXZ7hKQiBmi1OZTc4VSwi8V2TtmPAiMxqokKpvfDdcki3+W U7QR6sVHgW0vC61RLPmKBmYvwVtaFTxu58cy00X/0B/OIY9rZtnfN/bqXXNOR528Xzcr 3Vj5tMZOz/OIHjDeABHEouuvcqG6pJguqobdDuMoMrKlr6bNhIfbfxZiF4WUKg9uft6P 5D9w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :arc-authentication-results; bh=sdj9hgcN2BbiBkCjH9H5S6zXuQo+QYUyo7/UKfg8Wyc=; b=eJydHA1GNSLvCVNUFIXiiKQ5vhhCy0w4XtQK+g8pY5syylY66n/tD8g+A0ZI6PhFbS SY277NGKfwfFniNX75IfSPvh0uMCzxv2jlz/So0j5YjJXSezEdCjEqtDbJw5D1F04Pbh iVydik5aBHFoee1FomFV38YFKdtT7wZFCWjTsVxWMXaXPoBQPg41MvY78/7qcL9UwXTk L9zCtQneDuQwy69XKzCYSsmA+Kf4lGbs6COivBju9IAnYuFW0vk4tK26JLYzr/mcqzca Q+jeEGsAzzZdfftYyuUGBf91O0N240d17/v7QEaAkc3RhQeC98fnPBeHfbOpvHEq2m+g 8NyA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=stable-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 b34si3145112pld.632.2017.09.29.03.29.42; Fri, 29 Sep 2017 03:29:43 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of stable-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 stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=stable-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751801AbdI2K3l (ORCPT + 8 others); Fri, 29 Sep 2017 06:29:41 -0400 Received: from foss.arm.com ([217.140.101.70]:40672 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750927AbdI2K3l (ORCPT ); Fri, 29 Sep 2017 06:29:41 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 04B321435; Fri, 29 Sep 2017 03:29:41 -0700 (PDT) Received: from edgewater-inn.cambridge.arm.com (usa-sjc-imap-foss1.foss.arm.com [10.72.51.249]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id CAB983F3E1; Fri, 29 Sep 2017 03:29:40 -0700 (PDT) Received: by edgewater-inn.cambridge.arm.com (Postfix, from userid 1000) id B21F21AE17BD; Fri, 29 Sep 2017 11:29:55 +0100 (BST) From: Will Deacon To: catalin.marinas@arm.com Cc: linux-arm-kernel@lists.infradead.org, Will Deacon , Jon Masters , Timur Tabi , Subject: [PATCH] arm64: mm: Use READ_ONCE when dereferencing pointer to pte table Date: Fri, 29 Sep 2017 11:29:55 +0100 Message-Id: <1506680995-9000-1-git-send-email-will.deacon@arm.com> X-Mailer: git-send-email 2.1.4 Sender: stable-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: stable@vger.kernel.org On kernels built with support for transparent huge pages, different CPUs can access the PMD concurrently due to e.g. fast GUP or page_vma_mapped_walk and they must take care to use READ_ONCE to avoid value tearing or caching of stale values by the compiler. Unfortunately, these functions call into our pgtable macros, which don't use READ_ONCE, and compiler caching has been observed to cause the following crash during ext4 writeback: PC is at check_pte+0x20/0x170 LR is at page_vma_mapped_walk+0x2e0/0x540 [...] Process doio (pid: 2463, stack limit = 0xffff00000f2e8000) Call trace: [] check_pte+0x20/0x170 [] page_vma_mapped_walk+0x2e0/0x540 [] page_mkclean_one+0xac/0x278 [] rmap_walk_file+0xf0/0x238 [] rmap_walk+0x64/0xa0 [] page_mkclean+0x90/0xa8 [] clear_page_dirty_for_io+0x84/0x2a8 [] mpage_submit_page+0x34/0x98 [] mpage_process_page_bufs+0x164/0x170 [] mpage_prepare_extent_to_map+0x134/0x2b8 [] ext4_writepages+0x484/0xe30 [] do_writepages+0x44/0xe8 [] __filemap_fdatawrite_range+0xbc/0x110 [] file_write_and_wait_range+0x48/0xd8 [] ext4_sync_file+0x80/0x4b8 [] vfs_fsync_range+0x64/0xc0 [] SyS_msync+0x194/0x1e8 This is because page_vma_mapped_walk loads the PMD twice before calling pte_offset_map: the first time without READ_ONCE (where it gets all zeroes due to a concurrent pmdp_invalidate) and the second time with READ_ONCE (where it sees a valid table pointer due to a concurrent pmd_populate). However, the compiler inlines everything and caches the first value in a register, which is subsequently used in pte_offset_phys which returns a junk pointer that is later dereferenced when attempting to access the relevant pte. This patch fixes the issue by using READ_ONCE in pte_offset_phys to ensure that a stale value is not used. Whilst this is a point fix for a known failure (and simple to backport), a full fix moving all of our page table accessors over to {READ,WRITE}_ONCE and consistently using READ_ONCE in page_vma_mapped_walk is in the works for a future kernel release. Cc: Jon Masters Cc: Timur Tabi Cc: Fixes: f27176cfc363 ("mm: convert page_mkclean_one() to use page_vma_mapped_walk()") Tested-by: Richard Ruigrok Signed-off-by: Will Deacon --- arch/arm64/include/asm/pgtable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -- 2.1.4 diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index bc4e92337d16..b46e54c2399b 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -401,7 +401,7 @@ static inline phys_addr_t pmd_page_paddr(pmd_t pmd) /* Find an entry in the third-level page table. */ #define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) -#define pte_offset_phys(dir,addr) (pmd_page_paddr(*(dir)) + pte_index(addr) * sizeof(pte_t)) +#define pte_offset_phys(dir,addr) (pmd_page_paddr(READ_ONCE(*(dir))) + pte_index(addr) * sizeof(pte_t)) #define pte_offset_kernel(dir,addr) ((pte_t *)__va(pte_offset_phys((dir), (addr)))) #define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))