Received: by 10.223.176.46 with SMTP id f43csp2651516wra; Mon, 22 Jan 2018 00:55:49 -0800 (PST) X-Google-Smtp-Source: AH8x226hEie5KnIS/raRhIt4BBSSSt9SaWmGghjPIZ7NwZmxano4wIwkcvffGLdjM1PryAgPs7WD X-Received: by 10.101.70.140 with SMTP id h12mr6819470pgr.166.1516611349375; Mon, 22 Jan 2018 00:55:49 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516611349; cv=none; d=google.com; s=arc-20160816; b=N1un8QMhQeOJAeH75F5G85hczT2UkD37FKEmq1XkDaOEL25Uk8+cOOw060pKxm476R f3FXa2+smtegHg98MRA08OFoGcT7xmuB7gQ1vw59CLZSQ723yVjguEwI3+fD5oP9iIHD ytX9KUPhXfjX3+v/olmYuEyRFvwMs60SbyjvffKMawxeE9Nch49l/hKWqZJmmWCqdjKQ HpP/xb0NexoVbur/8WgDvObL5HaWU7vzk9iYNzN2e8jOKY/mcpDp0j45g0/UohrjYL/S e9jOilgyWnzHm14n+FTSaRemYw3HJcfFOS5aVnljBw+j4/CfKpKFrrrx0KlZyULeTnkH K42w== 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=ANacwTdOtUgNLXk2WWVmHzmhT7phz+xgFTFZYlxtNgM=; b=li4y1PJyjTbSAWcYkhfnIl/2PManSImpCt/56/JLK/x91ArIY8qSne5wGJtSY2vemH XaRrhf0pmQeSN9a9htu74yLTt8DypqU3NFuYI00pY93RSLKKoQ+Hnd/mov0k9PUHa2j6 JTuA4X50kl5pqZnoww6EeZk1IzaAB0FQ9Aw1nzA6CWgmcv2xwZ8cPl9M9D1e4GSEbNBs NiR8XvMXCD5j5hF/uDJNS3XAUzaqZXJ3f/2y4JJAW3htfxpHqSI2kVVe0yo2npesYa5I rof/PrI/cRwlp4YxrqY5uwcU7m7MQQMQKxQ1zfdXvhnAtx3kk+AMGVvsaOE1A0i3ftNm pXzA== 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 r80si13308999pfa.358.2018.01.22.00.55.35; Mon, 22 Jan 2018 00:55:49 -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; 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 S1753858AbeAVIyk (ORCPT + 99 others); Mon, 22 Jan 2018 03:54:40 -0500 Received: from mail.linuxfoundation.org ([140.211.169.12]:34338 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753834AbeAVIyg (ORCPT ); Mon, 22 Jan 2018 03:54:36 -0500 Received: from localhost (LFbn-1-12258-90.w90-92.abo.wanadoo.fr [90.92.71.90]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id B6C36F00; Mon, 22 Jan 2018 08:54:35 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, "Kirill A. Shutemov" , Michal Hocko , Linus Torvalds Subject: [PATCH 4.14 88/89] mm, page_vma_mapped: Drop faulty pointer arithmetics in check_pte() Date: Mon, 22 Jan 2018 09:46:08 +0100 Message-Id: <20180122084003.327064543@linuxfoundation.org> X-Mailer: git-send-email 2.16.0 In-Reply-To: <20180122083954.683903493@linuxfoundation.org> References: <20180122083954.683903493@linuxfoundation.org> User-Agent: quilt/0.65 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.14-stable review patch. If anyone has any objections, please let me know. ------------------ From: Kirill A. Shutemov commit 0d665e7b109d512b7cae3ccef6e8654714887844 upstream. Tetsuo reported random crashes under memory pressure on 32-bit x86 system and tracked down to change that introduced page_vma_mapped_walk(). The root cause of the issue is the faulty pointer math in check_pte(). As ->pte may point to an arbitrary page we have to check that they are belong to the section before doing math. Otherwise it may lead to weird results. It wasn't noticed until now as mem_map[] is virtually contiguous on flatmem or vmemmap sparsemem. Pointer arithmetic just works against all 'struct page' pointers. But with classic sparsemem, it doesn't because each section memap is allocated separately and so consecutive pfns crossing two sections might have struct pages at completely unrelated addresses. Let's restructure code a bit and replace pointer arithmetic with operations on pfns. Signed-off-by: Kirill A. Shutemov Reported-and-tested-by: Tetsuo Handa Acked-by: Michal Hocko Fixes: ace71a19cec5 ("mm: introduce page_vma_mapped_walk()") Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/swapops.h | 21 ++++++++++++++++ mm/page_vma_mapped.c | 63 ++++++++++++++++++++++++++++-------------------- 2 files changed, 59 insertions(+), 25 deletions(-) --- a/include/linux/swapops.h +++ b/include/linux/swapops.h @@ -124,6 +124,11 @@ static inline bool is_write_device_priva return unlikely(swp_type(entry) == SWP_DEVICE_WRITE); } +static inline unsigned long device_private_entry_to_pfn(swp_entry_t entry) +{ + return swp_offset(entry); +} + static inline struct page *device_private_entry_to_page(swp_entry_t entry) { return pfn_to_page(swp_offset(entry)); @@ -154,6 +159,11 @@ static inline bool is_write_device_priva return false; } +static inline unsigned long device_private_entry_to_pfn(swp_entry_t entry) +{ + return 0; +} + static inline struct page *device_private_entry_to_page(swp_entry_t entry) { return NULL; @@ -189,6 +199,11 @@ static inline int is_write_migration_ent return unlikely(swp_type(entry) == SWP_MIGRATION_WRITE); } +static inline unsigned long migration_entry_to_pfn(swp_entry_t entry) +{ + return swp_offset(entry); +} + static inline struct page *migration_entry_to_page(swp_entry_t entry) { struct page *p = pfn_to_page(swp_offset(entry)); @@ -218,6 +233,12 @@ static inline int is_migration_entry(swp { return 0; } + +static inline unsigned long migration_entry_to_pfn(swp_entry_t entry) +{ + return 0; +} + static inline struct page *migration_entry_to_page(swp_entry_t entry) { return NULL; --- a/mm/page_vma_mapped.c +++ b/mm/page_vma_mapped.c @@ -30,10 +30,29 @@ static bool map_pte(struct page_vma_mapp return true; } +/** + * check_pte - check if @pvmw->page is mapped at the @pvmw->pte + * + * page_vma_mapped_walk() found a place where @pvmw->page is *potentially* + * mapped. check_pte() has to validate this. + * + * @pvmw->pte may point to empty PTE, swap PTE or PTE pointing to arbitrary + * page. + * + * If PVMW_MIGRATION flag is set, returns true if @pvmw->pte contains migration + * entry that points to @pvmw->page or any subpage in case of THP. + * + * If PVMW_MIGRATION flag is not set, returns true if @pvmw->pte points to + * @pvmw->page or any subpage in case of THP. + * + * Otherwise, return false. + * + */ static bool check_pte(struct page_vma_mapped_walk *pvmw) { + unsigned long pfn; + if (pvmw->flags & PVMW_MIGRATION) { -#ifdef CONFIG_MIGRATION swp_entry_t entry; if (!is_swap_pte(*pvmw->pte)) return false; @@ -41,37 +60,31 @@ static bool check_pte(struct page_vma_ma if (!is_migration_entry(entry)) return false; - if (migration_entry_to_page(entry) - pvmw->page >= - hpage_nr_pages(pvmw->page)) { - return false; - } - if (migration_entry_to_page(entry) < pvmw->page) - return false; -#else - WARN_ON_ONCE(1); -#endif - } else { - if (is_swap_pte(*pvmw->pte)) { - swp_entry_t entry; - entry = pte_to_swp_entry(*pvmw->pte); - if (is_device_private_entry(entry) && - device_private_entry_to_page(entry) == pvmw->page) - return true; - } + pfn = migration_entry_to_pfn(entry); + } else if (is_swap_pte(*pvmw->pte)) { + swp_entry_t entry; - if (!pte_present(*pvmw->pte)) + /* Handle un-addressable ZONE_DEVICE memory */ + entry = pte_to_swp_entry(*pvmw->pte); + if (!is_device_private_entry(entry)) return false; - /* THP can be referenced by any subpage */ - if (pte_page(*pvmw->pte) - pvmw->page >= - hpage_nr_pages(pvmw->page)) { - return false; - } - if (pte_page(*pvmw->pte) < pvmw->page) + pfn = device_private_entry_to_pfn(entry); + } else { + if (!pte_present(*pvmw->pte)) return false; + + pfn = pte_pfn(*pvmw->pte); } + if (pfn < page_to_pfn(pvmw->page)) + return false; + + /* THP can be referenced by any subpage */ + if (pfn - page_to_pfn(pvmw->page) >= hpage_nr_pages(pvmw->page)) + return false; + return true; }