All of lore.kernel.org
 help / color / mirror / Atom feed
From: Gavin Shan <gshan@redhat.com>
To: linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org, anshuman.khandual@arm.com,
	catalin.marinas@arm.com, will@kernel.org,
	akpm@linux-foundation.org, shan.gavin@gmail.com
Subject: [PATCH] mm/debug_vm_pgtable: Fix corrupted PG_arch_1 by set_pmd_at()
Date: Fri,  2 Jul 2021 18:32:25 +0800	[thread overview]
Message-ID: <20210702103225.51448-1-gshan@redhat.com> (raw)

There are two addresses selected: random virtual address and physical
address corresponding to kernel symbol @start_kernel. During the PMD
tests in pmd_advanced_tests(), the physical address is aligned down
to the starting address of the huge page, whose size is 512MB on ARM64
when we have 64KB base page size. After that, set_pmd_at() is called
to populate the PMD entry. PG_arch_1, PG_dcache_clean on ARM64, is
set to the page flags. Unforunately, the page, corresponding to the
starting address of the huge page could be owned by buddy. It means
PG_arch_1 can be unconditionally set to page owned by buddy.

Afterwards, the page with PG_arch_1 set is fetched from buddy's free
area list, but fails the checking. It leads to the following warning
on ARM64:

   BUG: Bad page state in process memhog  pfn:08000
   page:0000000015c0a628 refcount:0 mapcount:0 \
        mapping:0000000000000000 index:0x1 pfn:0x8000
   flags: 0x7ffff8000000800(arch_1|node=0|zone=0|lastcpupid=0xfffff)
   raw: 07ffff8000000800 dead000000000100 dead000000000122 0000000000000000
   raw: 0000000000000001 0000000000000000 00000000ffffffff 0000000000000000
   page dumped because: PAGE_FLAGS_CHECK_AT_PREP flag(s) set

This fixes the issue by calling flush_dcache_page() after each call
to set_{pud, pmd, pte}_at() because PG_arch_1 isn't needed in any case.

Fixes: a5c3b9ffb0f4 ("mm/debug_vm_pgtable: add tests validating advanced arch page table helpers")
Cc: stable@vger.kernel.org # v5.9+
Signed-off-by: Gavin Shan <gshan@redhat.com>
---
 mm/debug_vm_pgtable.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 92bfc37300df..7dedf6c6dd25 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -29,6 +29,8 @@
 #include <linux/start_kernel.h>
 #include <linux/sched/mm.h>
 #include <linux/io.h>
+
+#include <asm/cacheflush.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
@@ -91,6 +93,7 @@ static void __init pte_advanced_tests(struct mm_struct *mm,
 				      unsigned long pfn, unsigned long vaddr,
 				      pgprot_t prot)
 {
+	struct page *page = pfn_to_page(pfn);
 	pte_t pte = pfn_pte(pfn, prot);
 
 	/*
@@ -102,6 +105,7 @@ static void __init pte_advanced_tests(struct mm_struct *mm,
 	pr_debug("Validating PTE advanced\n");
 	pte = pfn_pte(pfn, prot);
 	set_pte_at(mm, vaddr, ptep, pte);
+	flush_dcache_page(page);
 	ptep_set_wrprotect(mm, vaddr, ptep);
 	pte = ptep_get(ptep);
 	WARN_ON(pte_write(pte));
@@ -113,6 +117,7 @@ static void __init pte_advanced_tests(struct mm_struct *mm,
 	pte = pte_wrprotect(pte);
 	pte = pte_mkclean(pte);
 	set_pte_at(mm, vaddr, ptep, pte);
+	flush_dcache_page(page);
 	pte = pte_mkwrite(pte);
 	pte = pte_mkdirty(pte);
 	ptep_set_access_flags(vma, vaddr, ptep, pte, 1);
@@ -125,6 +130,7 @@ static void __init pte_advanced_tests(struct mm_struct *mm,
 	pte = pfn_pte(pfn, prot);
 	pte = pte_mkyoung(pte);
 	set_pte_at(mm, vaddr, ptep, pte);
+	flush_dcache_page(page);
 	ptep_test_and_clear_young(vma, vaddr, ptep);
 	pte = ptep_get(ptep);
 	WARN_ON(pte_young(pte));
@@ -186,6 +192,7 @@ static void __init pmd_advanced_tests(struct mm_struct *mm,
 				      unsigned long pfn, unsigned long vaddr,
 				      pgprot_t prot, pgtable_t pgtable)
 {
+	struct page *page = pfn_to_page(pfn);
 	pmd_t pmd;
 
 	if (!has_transparent_hugepage())
@@ -199,6 +206,7 @@ static void __init pmd_advanced_tests(struct mm_struct *mm,
 
 	pmd = pfn_pmd(pfn, prot);
 	set_pmd_at(mm, vaddr, pmdp, pmd);
+	flush_dcache_page(page);
 	pmdp_set_wrprotect(mm, vaddr, pmdp);
 	pmd = READ_ONCE(*pmdp);
 	WARN_ON(pmd_write(pmd));
@@ -210,6 +218,7 @@ static void __init pmd_advanced_tests(struct mm_struct *mm,
 	pmd = pmd_wrprotect(pmd);
 	pmd = pmd_mkclean(pmd);
 	set_pmd_at(mm, vaddr, pmdp, pmd);
+	flush_dcache_page(page);
 	pmd = pmd_mkwrite(pmd);
 	pmd = pmd_mkdirty(pmd);
 	pmdp_set_access_flags(vma, vaddr, pmdp, pmd, 1);
@@ -222,6 +231,7 @@ static void __init pmd_advanced_tests(struct mm_struct *mm,
 	pmd = pmd_mkhuge(pfn_pmd(pfn, prot));
 	pmd = pmd_mkyoung(pmd);
 	set_pmd_at(mm, vaddr, pmdp, pmd);
+	flush_dcache_page(page);
 	pmdp_test_and_clear_young(vma, vaddr, pmdp);
 	pmd = READ_ONCE(*pmdp);
 	WARN_ON(pmd_young(pmd));
@@ -334,6 +344,7 @@ static void __init pud_advanced_tests(struct mm_struct *mm,
 				      unsigned long pfn, unsigned long vaddr,
 				      pgprot_t prot)
 {
+	struct page *page = pfn_to_page(page);
 	pud_t pud;
 
 	if (!has_transparent_hugepage())
@@ -345,6 +356,7 @@ static void __init pud_advanced_tests(struct mm_struct *mm,
 
 	pud = pfn_pud(pfn, prot);
 	set_pud_at(mm, vaddr, pudp, pud);
+	flush_dcache_page(page);
 	pudp_set_wrprotect(mm, vaddr, pudp);
 	pud = READ_ONCE(*pudp);
 	WARN_ON(pud_write(pud));
@@ -358,6 +370,7 @@ static void __init pud_advanced_tests(struct mm_struct *mm,
 	pud = pud_wrprotect(pud);
 	pud = pud_mkclean(pud);
 	set_pud_at(mm, vaddr, pudp, pud);
+	flush_dcache_page(page);
 	pud = pud_mkwrite(pud);
 	pud = pud_mkdirty(pud);
 	pudp_set_access_flags(vma, vaddr, pudp, pud, 1);
@@ -373,6 +386,7 @@ static void __init pud_advanced_tests(struct mm_struct *mm,
 	pud = pfn_pud(pfn, prot);
 	pud = pud_mkyoung(pud);
 	set_pud_at(mm, vaddr, pudp, pud);
+	flush_dcache_page(page);
 	pudp_test_and_clear_young(vma, vaddr, pudp);
 	pud = READ_ONCE(*pudp);
 	WARN_ON(pud_young(pud));
@@ -604,6 +618,7 @@ static void __init pte_clear_tests(struct mm_struct *mm, pte_t *ptep,
 				   unsigned long pfn, unsigned long vaddr,
 				   pgprot_t prot)
 {
+	struct page *page = pfn_to_page(pfn);
 	pte_t pte = pfn_pte(pfn, prot);
 
 	pr_debug("Validating PTE clear\n");
@@ -611,6 +626,7 @@ static void __init pte_clear_tests(struct mm_struct *mm, pte_t *ptep,
 	pte = __pte(pte_val(pte) | RANDOM_ORVALUE);
 #endif
 	set_pte_at(mm, vaddr, ptep, pte);
+	flush_dcache_page(page);
 	barrier();
 	pte_clear(mm, vaddr, ptep);
 	pte = ptep_get(ptep);
-- 
2.23.0


             reply	other threads:[~2021-07-02 10:32 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-02 10:32 Gavin Shan [this message]
2021-07-02 18:10 ` [PATCH] mm/debug_vm_pgtable: Fix corrupted PG_arch_1 by set_pmd_at() kernel test robot
2021-07-02 18:10   ` kernel test robot
2021-07-03  0:30 ` Gavin Shan
2021-07-05  3:59 ` Anshuman Khandual
2021-07-06  5:09   ` Gavin Shan
2021-07-08  0:35 ` kernel test robot
2021-07-08  0:35   ` kernel test robot
2021-07-12  3:21   ` Anshuman Khandual
2021-07-12  3:21     ` Anshuman Khandual
2021-07-12  8:24     ` Gavin Shan
2021-07-12  8:24       ` Gavin Shan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210702103225.51448-1-gshan@redhat.com \
    --to=gshan@redhat.com \
    --cc=akpm@linux-foundation.org \
    --cc=anshuman.khandual@arm.com \
    --cc=catalin.marinas@arm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=shan.gavin@gmail.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.