summaryrefslogtreecommitdiffstats
path: root/arch/x86/power
diff options
context:
space:
mode:
authorDave Hansen <dave.hansen@linux.intel.com>2018-04-06 16:55:09 -0400
committerIngo Molnar <mingo@kernel.org>2018-04-12 03:04:22 -0400
commitfb43d6cb91ef57d9e58d5f69b423784ff4a4c374 (patch)
tree4785de6f0a6b6b3bf0ef8df64c400af3c34cdfbc /arch/x86/power
parent6baf4bec02dbc41645c3a5130ee15a8e1d62b80f (diff)
x86/mm: Do not auto-massage page protections
A PTE is constructed from a physical address and a pgprotval_t. __PAGE_KERNEL, for instance, is a pgprot_t and must be converted into a pgprotval_t before it can be used to create a PTE. This is done implicitly within functions like pfn_pte() by massage_pgprot(). However, this makes it very challenging to set bits (and keep them set) if your bit is being filtered out by massage_pgprot(). This moves the bit filtering out of pfn_pte() and friends. For users of PAGE_KERNEL*, filtering will be done automatically inside those macros but for users of __PAGE_KERNEL*, they need to do their own filtering now. Note that we also just move pfn_pte/pmd/pud() over to check_pgprot() instead of massage_pgprot(). This way, we still *look* for unsupported bits and properly warn about them if we find them. This might happen if an unfiltered __PAGE_KERNEL* value was passed in, for instance. - printk format warning fix from: Arnd Bergmann <arnd@arndb.de> - boot crash fix from: Tom Lendacky <thomas.lendacky@amd.com> - crash bisected by: Mike Galbraith <efault@gmx.de> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Reported-and-fixed-by: Arnd Bergmann <arnd@arndb.de> Fixed-by: Tom Lendacky <thomas.lendacky@amd.com> Bisected-by: Mike Galbraith <efault@gmx.de> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Borislav Petkov <bp@alien8.de> Cc: Dan Williams <dan.j.williams@intel.com> Cc: David Woodhouse <dwmw2@infradead.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Hugh Dickins <hughd@google.com> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Juergen Gross <jgross@suse.com> Cc: Kees Cook <keescook@google.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Nadav Amit <namit@vmware.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/20180406205509.77E1D7F6@viggo.jf.intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/power')
-rw-r--r--arch/x86/power/hibernate_64.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c
index 74a532989308..48b14b534897 100644
--- a/arch/x86/power/hibernate_64.c
+++ b/arch/x86/power/hibernate_64.c
@@ -51,6 +51,12 @@ static int set_up_temporary_text_mapping(pgd_t *pgd)
51 pmd_t *pmd; 51 pmd_t *pmd;
52 pud_t *pud; 52 pud_t *pud;
53 p4d_t *p4d = NULL; 53 p4d_t *p4d = NULL;
54 pgprot_t pgtable_prot = __pgprot(_KERNPG_TABLE);
55 pgprot_t pmd_text_prot = __pgprot(__PAGE_KERNEL_LARGE_EXEC);
56
57 /* Filter out unsupported __PAGE_KERNEL* bits: */
58 pgprot_val(pmd_text_prot) &= __default_kernel_pte_mask;
59 pgprot_val(pgtable_prot) &= __default_kernel_pte_mask;
54 60
55 /* 61 /*
56 * The new mapping only has to cover the page containing the image 62 * The new mapping only has to cover the page containing the image
@@ -81,15 +87,19 @@ static int set_up_temporary_text_mapping(pgd_t *pgd)
81 return -ENOMEM; 87 return -ENOMEM;
82 88
83 set_pmd(pmd + pmd_index(restore_jump_address), 89 set_pmd(pmd + pmd_index(restore_jump_address),
84 __pmd((jump_address_phys & PMD_MASK) | __PAGE_KERNEL_LARGE_EXEC)); 90 __pmd((jump_address_phys & PMD_MASK) | pgprot_val(pmd_text_prot)));
85 set_pud(pud + pud_index(restore_jump_address), 91 set_pud(pud + pud_index(restore_jump_address),
86 __pud(__pa(pmd) | _KERNPG_TABLE)); 92 __pud(__pa(pmd) | pgprot_val(pgtable_prot)));
87 if (p4d) { 93 if (p4d) {
88 set_p4d(p4d + p4d_index(restore_jump_address), __p4d(__pa(pud) | _KERNPG_TABLE)); 94 p4d_t new_p4d = __p4d(__pa(pud) | pgprot_val(pgtable_prot));
89 set_pgd(pgd + pgd_index(restore_jump_address), __pgd(__pa(p4d) | _KERNPG_TABLE)); 95 pgd_t new_pgd = __pgd(__pa(p4d) | pgprot_val(pgtable_prot));
96
97 set_p4d(p4d + p4d_index(restore_jump_address), new_p4d);
98 set_pgd(pgd + pgd_index(restore_jump_address), new_pgd);
90 } else { 99 } else {
91 /* No p4d for 4-level paging: point the pgd to the pud page table */ 100 /* No p4d for 4-level paging: point the pgd to the pud page table */
92 set_pgd(pgd + pgd_index(restore_jump_address), __pgd(__pa(pud) | _KERNPG_TABLE)); 101 pgd_t new_pgd = __pgd(__pa(p4d) | pgprot_val(pgtable_prot));
102 set_pgd(pgd + pgd_index(restore_jump_address), new_pgd);
93 } 103 }
94 104
95 return 0; 105 return 0;