diff options
author | Joerg Roedel <jroedel@suse.de> | 2018-04-17 09:27:16 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2018-04-17 09:43:01 -0400 |
commit | d6ef1f194b7569af8b8397876dc9ab07649d63cb (patch) | |
tree | 9d7bd7b181f1d7f32abb559812163b8eba076d8b | |
parent | 1340ccfa9a9afefdbab90d7935d4ed19817e37c2 (diff) |
x86/mm: Prevent kernel Oops in PTDUMP code with HIGHPTE=y
The walk_pte_level() function just uses __va to get the virtual address of
the PTE page, but that breaks when the PTE page is not in the direct
mapping with HIGHPTE=y.
The result is an unhandled kernel paging request at some random address
when accessing the current_kernel or current_user file.
Use the correct API to access PTE pages.
Fixes: fe770bf0310d ('x86: clean up the page table dumper and add 32-bit support')
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org
Cc: jgross@suse.com
Cc: JBeulich@suse.com
Cc: hpa@zytor.com
Cc: aryabinin@virtuozzo.com
Cc: kirill.shutemov@linux.intel.com
Link: https://lkml.kernel.org/r/1523971636-4137-1-git-send-email-joro@8bytes.org
-rw-r--r-- | arch/x86/mm/dump_pagetables.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c index 62a7e9f65dec..cc7ff5957194 100644 --- a/arch/x86/mm/dump_pagetables.c +++ b/arch/x86/mm/dump_pagetables.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
20 | #include <linux/seq_file.h> | 20 | #include <linux/seq_file.h> |
21 | #include <linux/highmem.h> | ||
21 | 22 | ||
22 | #include <asm/pgtable.h> | 23 | #include <asm/pgtable.h> |
23 | 24 | ||
@@ -334,16 +335,16 @@ static void walk_pte_level(struct seq_file *m, struct pg_state *st, pmd_t addr, | |||
334 | pgprotval_t eff_in, unsigned long P) | 335 | pgprotval_t eff_in, unsigned long P) |
335 | { | 336 | { |
336 | int i; | 337 | int i; |
337 | pte_t *start; | 338 | pte_t *pte; |
338 | pgprotval_t prot, eff; | 339 | pgprotval_t prot, eff; |
339 | 340 | ||
340 | start = (pte_t *)pmd_page_vaddr(addr); | ||
341 | for (i = 0; i < PTRS_PER_PTE; i++) { | 341 | for (i = 0; i < PTRS_PER_PTE; i++) { |
342 | prot = pte_flags(*start); | ||
343 | eff = effective_prot(eff_in, prot); | ||
344 | st->current_address = normalize_addr(P + i * PTE_LEVEL_MULT); | 342 | st->current_address = normalize_addr(P + i * PTE_LEVEL_MULT); |
343 | pte = pte_offset_map(&addr, st->current_address); | ||
344 | prot = pte_flags(*pte); | ||
345 | eff = effective_prot(eff_in, prot); | ||
345 | note_page(m, st, __pgprot(prot), eff, 5); | 346 | note_page(m, st, __pgprot(prot), eff, 5); |
346 | start++; | 347 | pte_unmap(pte); |
347 | } | 348 | } |
348 | } | 349 | } |
349 | #ifdef CONFIG_KASAN | 350 | #ifdef CONFIG_KASAN |