x86, mm: PTI Global page fixes for 4.17
Subsystems (4)
Dave Hansen
maintainercover x86, mm: PTI Global page fixes for 4.17
There have been a number of reports about issues with the patches that restore the Global PTE bit when using KPIT. This set resolves all of the issues that have been reported.
These have been pushed out to a git tree where 0day should be chewing on them. Considering the troubles thus far, we should probably wait for 0day to spend _some_ time on these fixes before these get merged.
Dave Hansen
maintainerPATCH 1/5 x86, pti: fix boot problems from Global-bit setting
From: Dave Hansen <[email protected]>
Part of the global bit _setting_ patches also includes clearing the Global bit when we do not want it. That is done with set_memory_nonglobal(), which uses change_page_attr_clear() in pageattr.c under the covers.
The TLB flushing code inside pageattr.c has has checks like BUG_ON(irqs_disabled()), looking for interrupt disabling that might cause deadlocks. But, these also trip in early boot on certain preempt configurations. Just copy the existing BUG_ON() sequence from cpa_flush_range() to the other two sites and check for early boot.
---
b/arch/x86/mm/pageattr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/mm/pageattr.c renamed from arch/x86/mm/pageattr.c~pti-glb-boot-problem-fix +2 -2
@@ -172,7 +172,7 @@ static void __cpa_flush_all(void *arg)static void cpa_flush_all (unsigned long cache) { -BUG_ON (irqs_disabled ()); +BUG_ON (irqs_disabled () && !early_boot_irqs_disabled);on_each_cpu (__cpa_flush_all, (void *) cache,1 ); }
@@ -236,7 +236,7 @@ static void cpa_flush_array(unsigned lonunsigned long do_wbinvd = cache && numpages >=1024 ;/* 4M threshold */ #endif -BUG_ON (irqs_disabled ()); +BUG_ON (irqs_disabled () && !early_boot_irqs_disabled);on_each_cpu (__cpa_flush_all, (void *) do_wbinvd,1 );
_
Re: [PATCH 1/5] x86, pti: fix boot problems from Global-bit setting
Hi,
Quoted 11 lines · Dave Hansen
Part of the global bit _setting_ patches also includes clearing the Global bit when we do not want it. That is done with
set_memory_nonglobal(), which useschange_page_attr_clear()inpageattr.cunder the covers.The TLB flushing code inside
pageattr.chas has checks like BUG_ON(irqs_disabled()), looking for interrupt disabling that might cause deadlocks. But, these also trip in early boot on certain preempt configurations. Just copy the existingBUG_ON()sequence fromcpa_flush_range()to the other two sites and check for early boot.
Quoted 4 lines
Signed-off-by Dave Hansen <[email protected]>Fixes 39114b7a7 (x86/pti: Never implicitly clear _PAGE_GLOBAL for kernel image)Reported-by Mariusz Ceier <[email protected]>Reported-by Aaro Koskinen <[email protected]>
A.
Quoted 43 lines
Cc Andrea Arcangeli <[email protected]>Cc Andy Lutomirski <[email protected]>Cc Arjan van de Ven <[email protected]>Cc Borislav Petkov <[email protected]>Cc Dan Williams <[email protected]>Cc David Woodhouse <[email protected]>Cc Greg Kroah-Hartman <[email protected]>Cc Hugh Dickins <[email protected]>Cc Josh Poimboeuf <[email protected]>Cc Juergen Gross <[email protected]>Cc Kees Cook <[email protected]>Cc Linus Torvalds <[email protected]>Cc Nadav Amit <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Thomas Gleixner <[email protected]>---
b/arch/x86/mm/pageattr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)diff -puN
arch/x86/mm/pageattr.c~pti-glb-boot-problem-fixarch/x86/mm/pageattr.carch/x86/mm/pageattr.c renamed from arch/x86/mm/pageattr.c~pti-glb-boot-problem-fix +2
-2@@ -172,7 +172,7 @@ static void __cpa_flush_all(void *arg)static void cpa_flush_all (unsigned long cache) { -BUG_ON (irqs_disabled ()); +BUG_ON (irqs_disabled () && !early_boot_irqs_disabled);on_each_cpu (__cpa_flush_all, (void *) cache,1 ); }@@ -236,7 +236,7 @@ static void cpa_flush_array(unsigned lonunsigned long do_wbinvd = cache && numpages >=1024 ;/* 4M threshold */ #endif -BUG_ON (irqs_disabled ()); +BUG_ON (irqs_disabled () && !early_boot_irqs_disabled);on_each_cpu (__cpa_flush_all, (void *) do_wbinvd,1 );_
tip-bot for Dave Hansen
merge bot[tip:x86/pti] x86/pti: Fix boot problems from Global-bit setting
In reply to Dave Hansenx86/pti: Fix boot problems from Global-bit setting
Commit-ID: 16dce603adc9de4237b7bf2ff5c5290f34373e7b Gitweb: https://git.kernel.org/tip/16dce603adc9de4237b7bf2ff5c5290f34373e7b Author: Dave Hansen <[email protected]> AuthorDate: Fri, 20 Apr 2018 15:20:19 -0700 Committer: Thomas Gleixner <[email protected]> CommitDate: Tue, 24 Apr 2018 09:50:53 +0200
x86/pti: Fix boot problems from Global-bit setting
Part of the global bit _setting_ patches also includes clearing the Global bit when it should not be enabled. That is done with set_memory_nonglobal(), which uses change_page_attr_clear() in pageattr.c under the covers.
The TLB flushing code inside pageattr.c has has checks like BUG_ON(irqs_disabled()), looking for interrupt disabling that might cause deadlocks. But, these also trip in early boot on certain preempt configurations. Just copy the existing BUG_ON() sequence from cpa_flush_range() to the other two sites and check for early boot.
--- arch/x86/mm/pageattr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/mm/pageattr.c +2 -2
@@ -172,7 +172,7 @@ static void __cpa_flush_all(void *arg)static void cpa_flush_all (unsigned long cache) { -BUG_ON (irqs_disabled ()); +BUG_ON (irqs_disabled () && !early_boot_irqs_disabled);on_each_cpu (__cpa_flush_all, (void *) cache,1 ); }
@@ -236,7 +236,7 @@ static void cpa_flush_array(unsigned long *start, int numpages, int cache,unsigned long do_wbinvd = cache && numpages >=1024 ;/* 4M threshold */ #endif -BUG_ON (irqs_disabled ()); +BUG_ON (irqs_disabled () && !early_boot_irqs_disabled);on_each_cpu (__cpa_flush_all, (void *) do_wbinvd,1 );
tip-bot for Dave Hansen
merge bot[tip:x86/pti] x86/pti: Fix boot problems from Global-bit setting
In reply to Dave Hansenx86/pti: Fix boot problems from Global-bit setting
Commit-ID: d2479a30499d93377d3ab10b7822bc5f10ed7f22 Gitweb: https://git.kernel.org/tip/d2479a30499d93377d3ab10b7822bc5f10ed7f22 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 20 Apr 2018 15:20:19 -0700 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 25 Apr 2018 11:02:50 +0200
x86/pti: Fix boot problems from Global-bit setting
commit 16dce603adc9de4237b7bf2ff5c5290f34373e7b
Part of the global bit _setting_ patches also includes clearing the Global bit when it should not be enabled. That is done with set_memory_nonglobal(), which uses change_page_attr_clear() in pageattr.c under the covers.
The TLB flushing code inside pageattr.c has has checks like BUG_ON(irqs_disabled()), looking for interrupt disabling that might cause deadlocks. But, these also trip in early boot on certain preempt configurations. Just copy the existing BUG_ON() sequence from cpa_flush_range() to the other two sites and check for early boot.
--- arch/x86/mm/pageattr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/mm/pageattr.c +2 -2
@@ -172,7 +172,7 @@ static void __cpa_flush_all(void *arg)static void cpa_flush_all (unsigned long cache) { -BUG_ON (irqs_disabled ()); +BUG_ON (irqs_disabled () && !early_boot_irqs_disabled);on_each_cpu (__cpa_flush_all, (void *) cache,1 ); }
@@ -236,7 +236,7 @@ static void cpa_flush_array(unsigned long *start, int numpages, int cache,unsigned long do_wbinvd = cache && numpages >=1024 ;/* 4M threshold */ #endif -BUG_ON (irqs_disabled ()); +BUG_ON (irqs_disabled () && !early_boot_irqs_disabled);on_each_cpu (__cpa_flush_all, (void *) do_wbinvd,1 );
Dave Hansen
maintainerPATCH 2/5 x86, pti: fix boot warning from Global-bit setting
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
The pageattr.c code attempts to process "faults" when it goes looking for PTEs to change and finds non-present entries. It allows these faults in the linear map which is "expected to have holes", but WARN()s about them elsewhere, like when called on the kernel image.
However, we are now calling change_page_attr_clear() on the kernel image in the process of trying to clear the Global bit.
This trips the warning in __cpa_process_fault() if a non-present PTE is encountered in the kernel image. The "holes" in the kernel image result from free_init_pages()'s use of set_memory_np(). These holes are totally fine, and result from normal operation, just as they would be in the kernel linear map.
Just silence the warning when holes in the kernel image are encountered.
---
b/arch/x86/mm/pageattr.c | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-)
arch/x86/mm/pageattr.c renamed from arch/x86/mm/pageattr.c~pti-glb-warning-inpageattr +31 -10
@@ -93,6 +93,18 @@ void arch_report_meminfo(struct seq_filestatic inline void split_page_count (int level) { }#endif +static inline int +within (unsigned long addr,unsigned long start,unsigned long end) +{ +return addr >= start && addr < end; +} + +static inline int +within_inclusive (unsigned long addr,unsigned long start,unsigned long end) +{ +return addr >= start && addr <= end; +} +#ifdef CONFIG_X86_64 static inline unsigned long highmap_start_pfn (void )
@@ -106,20 +118,26 @@ static inline unsigned long highmap_end_ return __pa_symbol(roundup(_brk_end, PMD_SIZE) - 1) >> PAGE_SHIFT; } -#endif - -static inline int -within (unsigned long addr,unsigned long start,unsigned long end) +static bool __cpa_pfn_in_highmap (unsigned long pfn) { -return addr >= start && addr < end; +/* +* Kernel text has an alias mapping at a high address, known +* here as "highmap". +*/ +return within_inclusive (pfn,highmap_start_pfn (), +highmap_end_pfn ()); } -static inline int -within_inclusive (unsigned long addr,unsigned long start,unsigned long end) +#else + +static bool __cpa_pfn_in_highmap (unsigned long pfn) { -return addr >= start && addr <= end; +/* There is no highmap on 32-bit */ +return false; } +#endif +/* * Flushing functions */
@@ -1183,6 +1201,10 @@ static int __cpa_process_fault(struct cp cpa->numpages =1 ; cpa->pfn =__pa (vaddr) >>PAGE_SHIFT ;return 0 ; + + }else if (__cpa_pfn_in_highmap (cpa->pfn)) { +/* Faults in the highmap are OK, so do not warn: */ +return -EFAULT ; }else { WARN(1, KERN_WARNING "CPA: called for zero pte. " "vaddr = %lx cpa->vaddr = %lx\n", vaddr,
@@ -1335,8 +1357,7 @@ static int cpa_process_alias(struct cpa_* to touch the high mapped kernel as well: */ if (!within (vaddr, (unsigned long )_text, _brk_end) && -within_inclusive (cpa->pfn,highmap_start_pfn (), -highmap_end_pfn ())) { +__cpa_pfn_in_highmap (cpa->pfn)) {unsigned long temp_cpa_vaddr = (cpa->pfn <<PAGE_SHIFT ) + __START_KERNEL_map - phys_base; alias_cpa = *cpa;
_
Re: [PATCH 2/5] x86, pti: fix boot warning from Global-bit setting
Hi,
Quoted 14 lines · Dave Hansen
The
pageattr.ccode attempts to process "faults" when it goes looking for PTEs to change and finds non-present entries. It allows these faults in the linear map which is "expected to have holes", but WARN()s about them elsewhere, like when called on the kernel image.However, we are now calling
change_page_attr_clear()on the kernel image in the process of trying to clear the Global bit.This trips the warning in
__cpa_process_fault()if a non-present PTE is encountered in the kernel image. The "holes" in the kernel image result from free_init_pages()'s use ofset_memory_np(). These holes are totally fine, and result from normal operation, just as they would be in the kernel linear map.
Quoted 6 lines
Just silence the warning when holes in the kernel image are encountered.
Signed-off-by Dave Hansen <[email protected]>Fixes 39114b7a7 (x86/pti: Never implicitly clear _PAGE_GLOBAL for kernel image)Reported-by Mariusz Ceier <[email protected]>Reported-by Aaro Koskinen <[email protected]>
A.
Quoted 100 lines
Cc Andrea Arcangeli <[email protected]>Cc Andy Lutomirski <[email protected]>Cc Arjan van de Ven <[email protected]>Cc Borislav Petkov <[email protected]>Cc Dan Williams <[email protected]>Cc David Woodhouse <[email protected]>Cc Greg Kroah-Hartman <[email protected]>Cc Hugh Dickins <[email protected]>Cc Josh Poimboeuf <[email protected]>Cc Juergen Gross <[email protected]>Cc Kees Cook <[email protected]>Cc Linus Torvalds <[email protected]>Cc Nadav Amit <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Thomas Gleixner <[email protected]>---
b/arch/x86/mm/pageattr.c | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-)diff -puN
arch/x86/mm/pageattr.c~pti-glb-warning-inpageattrarch/x86/mm/pageattr.carch/x86/mm/pageattr.c renamed from arch/x86/mm/pageattr.c~pti-glb-warning-inpageattr +31
-10@@ -93,6 +93,18 @@ void arch_report_meminfo(struct seq_filestatic inline void split_page_count (int level) { }#endif +static inline int +within (unsigned long addr,unsigned long start,unsigned long end) +{ +return addr >= start && addr < end; +} + +static inline int +within_inclusive (unsigned long addr,unsigned long start,unsigned long end) +{ +return addr >= start && addr <= end; +} +#ifdef CONFIG_X86_64 static inline unsigned long highmap_start_pfn (void )@@ -106,20 +118,26 @@ static inline unsigned long highmap_end_ return __pa_symbol(roundup(_brk_end, PMD_SIZE) - 1) >> PAGE_SHIFT; } -#endif - -static inline int -within (unsigned long addr,unsigned long start,unsigned long end) +static bool __cpa_pfn_in_highmap (unsigned long pfn) { -return addr >= start && addr < end; +/* +* Kernel text has an alias mapping at a high address, known +* here as "highmap". +*/ +return within_inclusive (pfn,highmap_start_pfn (), +highmap_end_pfn ()); } -static inline int -within_inclusive (unsigned long addr,unsigned long start,unsigned long end) +#else + +static bool __cpa_pfn_in_highmap (unsigned long pfn) { -return addr >= start && addr <= end; +/* There is no highmap on 32-bit */ +return false; } +#endif +/* * Flushing functions */ @@ -1183,6 +1201,10 @@ static int __cpa_process_fault(struct cp cpa->numpages =1 ; cpa->pfn =__pa (vaddr) >>PAGE_SHIFT ;return 0 ; + + }else if (__cpa_pfn_in_highmap (cpa->pfn)) { +/* Faults in the highmap are OK, so do not warn: */ +return -EFAULT ; }else { WARN(1, KERN_WARNING "CPA: called for zero pte. " "vaddr = %lx cpa->vaddr = %lx\n", vaddr,@@ -1335,8 +1357,7 @@ static int cpa_process_alias(struct cpa_* to touch the high mapped kernel as well: */ if (!within (vaddr, (unsigned long )_text, _brk_end) && -within_inclusive (cpa->pfn,highmap_start_pfn (), -highmap_end_pfn ())) { +__cpa_pfn_in_highmap (cpa->pfn)) {unsigned long temp_cpa_vaddr = (cpa->pfn <<PAGE_SHIFT ) + __START_KERNEL_map - phys_base; alias_cpa = *cpa;_
tip-bot for Dave Hansen
merge bot[tip:x86/pti] x86/pti: Fix boot warning from Global-bit setting
In reply to Dave Hansenx86/pti: Fix boot warning from Global-bit setting
Commit-ID: 231df823c4f04176f607afc4576c989895cff40e Gitweb: https://git.kernel.org/tip/231df823c4f04176f607afc4576c989895cff40e Author: Dave Hansen <[email protected]> AuthorDate: Fri, 20 Apr 2018 15:20:21 -0700 Committer: Thomas Gleixner <[email protected]> CommitDate: Tue, 24 Apr 2018 09:50:53 +0200
x86/pti: Fix boot warning from Global-bit setting
The pageattr.c code attempts to process "faults" when it goes looking for PTEs to change and finds non-present entries. It allows these faults in the linear map which is "expected to have holes", but WARN()s about them elsewhere, like when called on the kernel image.
However, change_page_attr_clear() is now called on the kernel image in the process of trying to clear the Global bit.
This trips the warning in __cpa_process_fault() if a non-present PTE is encountered in the kernel image. The "holes" in the kernel image result from free_init_pages()'s use of set_memory_np(). These holes are totally fine, and result from normal operation, just as they would be in the kernel linear map.
Just silence the warning when holes in the kernel image are encountered.
--- arch/x86/mm/pageattr.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-)
arch/x86/mm/pageattr.c +30 -10
@@ -93,6 +93,18 @@ void arch_report_meminfo(struct seq_file *m)static inline void split_page_count (int level) { }#endif +static inline int +within (unsigned long addr,unsigned long start,unsigned long end) +{ +return addr >= start && addr < end; +} + +static inline int +within_inclusive (unsigned long addr,unsigned long start,unsigned long end) +{ +return addr >= start && addr <= end; +} +#ifdef CONFIG_X86_64 static inline unsigned long highmap_start_pfn (void )
@@ -106,20 +118,25 @@ static inline unsigned long highmap_end_pfn(void) return __pa_symbol(roundup(_brk_end, PMD_SIZE) - 1) >> PAGE_SHIFT; } -#endif - -static inline int -within (unsigned long addr,unsigned long start,unsigned long end) +static bool __cpa_pfn_in_highmap (unsigned long pfn) { -return addr >= start && addr < end; +/* +* Kernel text has an alias mapping at a high address, known +* here as "highmap". +*/ +return within_inclusive (pfn,highmap_start_pfn (),highmap_end_pfn ()); } -static inline int -within_inclusive (unsigned long addr,unsigned long start,unsigned long end) +#else + +static bool __cpa_pfn_in_highmap (unsigned long pfn) { -return addr >= start && addr <= end; +/* There is no highmap on 32-bit */ +return false; } +#endif +/* * Flushing functions */
@@ -1183,6 +1200,10 @@ static int __cpa_process_fault(struct cpa_data *cpa, unsigned long vaddr, cpa->numpages =1 ; cpa->pfn =__pa (vaddr) >>PAGE_SHIFT ;return 0 ; + + }else if (__cpa_pfn_in_highmap (cpa->pfn)) { +/* Faults in the highmap are OK, so do not warn: */ +return -EFAULT ; }else { WARN(1, KERN_WARNING "CPA: called for zero pte. " "vaddr = %lx cpa->vaddr = %lx\n", vaddr,
@@ -1335,8 +1356,7 @@ static int cpa_process_alias(struct cpa_data *cpa)* to touch the high mapped kernel as well: */ if (!within (vaddr, (unsigned long )_text, _brk_end) && -within_inclusive (cpa->pfn,highmap_start_pfn (), -highmap_end_pfn ())) { +__cpa_pfn_in_highmap (cpa->pfn)) {unsigned long temp_cpa_vaddr = (cpa->pfn <<PAGE_SHIFT ) + __START_KERNEL_map - phys_base; alias_cpa = *cpa;
tip-bot for Dave Hansen
merge bot[tip:x86/pti] x86/pti: Fix boot warning from Global-bit setting
In reply to Dave Hansenx86/pti: Fix boot warning from Global-bit setting
Commit-ID: 58e65b51e6f9b9dd94a25ff2b2772222e0358099 Gitweb: https://git.kernel.org/tip/58e65b51e6f9b9dd94a25ff2b2772222e0358099 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 20 Apr 2018 15:20:21 -0700 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 25 Apr 2018 11:02:50 +0200
x86/pti: Fix boot warning from Global-bit setting
commit 231df823c4f04176f607afc4576c989895cff40e
The pageattr.c code attempts to process "faults" when it goes looking for PTEs to change and finds non-present entries. It allows these faults in the linear map which is "expected to have holes", but WARN()s about them elsewhere, like when called on the kernel image.
However, change_page_attr_clear() is now called on the kernel image in the process of trying to clear the Global bit.
This trips the warning in __cpa_process_fault() if a non-present PTE is encountered in the kernel image. The "holes" in the kernel image result from free_init_pages()'s use of set_memory_np(). These holes are totally fine, and result from normal operation, just as they would be in the kernel linear map.
Just silence the warning when holes in the kernel image are encountered.
--- arch/x86/mm/pageattr.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-)
arch/x86/mm/pageattr.c +30 -10
@@ -93,6 +93,18 @@ void arch_report_meminfo(struct seq_file *m)static inline void split_page_count (int level) { }#endif +static inline int +within (unsigned long addr,unsigned long start,unsigned long end) +{ +return addr >= start && addr < end; +} + +static inline int +within_inclusive (unsigned long addr,unsigned long start,unsigned long end) +{ +return addr >= start && addr <= end; +} +#ifdef CONFIG_X86_64 static inline unsigned long highmap_start_pfn (void )
@@ -106,20 +118,25 @@ static inline unsigned long highmap_end_pfn(void) return __pa_symbol(roundup(_brk_end, PMD_SIZE) - 1) >> PAGE_SHIFT; } -#endif - -static inline int -within (unsigned long addr,unsigned long start,unsigned long end) +static bool __cpa_pfn_in_highmap (unsigned long pfn) { -return addr >= start && addr < end; +/* +* Kernel text has an alias mapping at a high address, known +* here as "highmap". +*/ +return within_inclusive (pfn,highmap_start_pfn (),highmap_end_pfn ()); } -static inline int -within_inclusive (unsigned long addr,unsigned long start,unsigned long end) +#else + +static bool __cpa_pfn_in_highmap (unsigned long pfn) { -return addr >= start && addr <= end; +/* There is no highmap on 32-bit */ +return false; } +#endif +/* * Flushing functions */
@@ -1183,6 +1200,10 @@ static int __cpa_process_fault(struct cpa_data *cpa, unsigned long vaddr, cpa->numpages =1 ; cpa->pfn =__pa (vaddr) >>PAGE_SHIFT ;return 0 ; + + }else if (__cpa_pfn_in_highmap (cpa->pfn)) { +/* Faults in the highmap are OK, so do not warn: */ +return -EFAULT ; }else { WARN(1, KERN_WARNING "CPA: called for zero pte. " "vaddr = %lx cpa->vaddr = %lx\n", vaddr,
@@ -1335,8 +1356,7 @@ static int cpa_process_alias(struct cpa_data *cpa)* to touch the high mapped kernel as well: */ if (!within (vaddr, (unsigned long )_text, _brk_end) && -within_inclusive (cpa->pfn,highmap_start_pfn (), -highmap_end_pfn ())) { +__cpa_pfn_in_highmap (cpa->pfn)) {unsigned long temp_cpa_vaddr = (cpa->pfn <<PAGE_SHIFT ) + __START_KERNEL_map - phys_base; alias_cpa = *cpa;
Dave Hansen
maintainerPATCH 3/5 x86, pti: reduce amount of kernel text allowed to be Global
In reply to Dave HansenKees reported to me that I made too much of the kernel image global. It was far more than just text:
I think this is too much set global: _end is after data, bss, and brk, and all kinds of other stuff that could hold secrets. I think this should match what mark_rodata_ro() is doing.
This does exactly that. We use __end_rodata_hpage_align as our marker both because it is huge-page-aligned and it does not contain any sections we expect to hold secrets.
Kees's logic was that r/o data is in the kernel image anyway and, in the case of traditional distributions, can be freely downloaded from the web, so there's no reason to hide it.
---
b/arch/x86/mm/pti.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
arch/x86/mm/pti.c renamed from arch/x86/mm/pti.c~pti-glb-too-much-mapped +13 -3
@@ -430,12 +430,24 @@ static inline bool pti_kernel_image_glob*/ void pti_clone_kernel_text (void ) { +/* +* rodata is part of the kernel image and is normally +* readable on the filesystem or on the web. But, do not +* clone the areas past rodata, they might contain secrets. +*/ unsigned long start =PFN_ALIGN (_text); -unsigned long end =ALIGN ((unsigned long )_end,PMD_PAGE_SIZE ); +unsigned long end = (unsigned long )__end_rodata_hpage_align;if (!pti_kernel_image_global_ok ())return ; +pr_debug ("mapping partial kernel image into user address space\n" ); + +/* +* Note that this will undo _some_ of the work that +* pti_set_kernel_image_nonglobal() did to clear the +* global bit. +*/ pti_clone_pmds (start, end, _PAGE_RW); }
@@ -458,8 +470,6 @@ void pti_set_kernel_image_nonglobal(voidif (pti_kernel_image_global_ok ())return ; -pr_debug ("set kernel image non-global\n" ); -set_memory_nonglobal (start, (end - start) >>PAGE_SHIFT ); }
_
tip-bot for Dave Hansen
merge bot[tip:x86/pti] x86, pti: Reduce amount of kernel text allowed to be Global
x86, pti: Reduce amount of kernel text allowed to be Global
Commit-ID: abb67605203687c8b7943d760638d0301787f8d9 Gitweb: https://git.kernel.org/tip/abb67605203687c8b7943d760638d0301787f8d9 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 20 Apr 2018 15:20:23 -0700 Committer: Thomas Gleixner <[email protected]> CommitDate: Tue, 24 Apr 2018 09:50:54 +0200
x86, pti: Reduce amount of kernel text allowed to be Global
Kees reported to me that I made too much of the kernel image global. It was far more than just text:
I think this is too much set global: _end is after data, bss, and brk, and all kinds of other stuff that could hold secrets. I think this should match what mark_rodata_ro() is doing.
This does exactly that. We use __end_rodata_hpage_align as our marker both because it is huge-page-aligned and it does not contain any sections we expect to hold secrets.
Kees's logic was that r/o data is in the kernel image anyway and, in the case of traditional distributions, can be freely downloaded from the web, so there's no reason to hide it.
--- arch/x86/mm/pti.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
arch/x86/mm/pti.c +13 -3
@@ -430,12 +430,24 @@ static inline bool pti_kernel_image_global_ok(void)*/ void pti_clone_kernel_text (void ) { +/* +* rodata is part of the kernel image and is normally +* readable on the filesystem or on the web. But, do not +* clone the areas past rodata, they might contain secrets. +*/ unsigned long start =PFN_ALIGN (_text); -unsigned long end =ALIGN ((unsigned long )_end,PMD_PAGE_SIZE ); +unsigned long end = (unsigned long )__end_rodata_hpage_align;if (!pti_kernel_image_global_ok ())return ; +pr_debug ("mapping partial kernel image into user address space\n" ); + +/* +* Note that this will undo _some_ of the work that +* pti_set_kernel_image_nonglobal() did to clear the +* global bit. +*/ pti_clone_pmds (start, end, _PAGE_RW); }
@@ -458,8 +470,6 @@ void pti_set_kernel_image_nonglobal(void)if (pti_kernel_image_global_ok ())return ; -pr_debug ("set kernel image non-global\n" ); -set_memory_nonglobal (start, (end - start) >>PAGE_SHIFT ); }
tip-bot for Dave Hansen
merge bot[tip:x86/pti] x86/pti: Reduce amount of kernel text allowed to be Global
In reply to Dave Hansenx86/pti: Reduce amount of kernel text allowed to be Global
Commit-ID: a44ca8f5a30c008b54d07b00eed4eae7f169fcd0 Gitweb: https://git.kernel.org/tip/a44ca8f5a30c008b54d07b00eed4eae7f169fcd0 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 20 Apr 2018 15:20:23 -0700 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 25 Apr 2018 11:02:50 +0200
x86/pti: Reduce amount of kernel text allowed to be Global
commit abb67605203687c8b7943d760638d0301787f8d9
Kees reported to me that I made too much of the kernel image global. It was far more than just text:
I think this is too much set global: _end is after data, bss, and brk, and all kinds of other stuff that could hold secrets. I think this should match what mark_rodata_ro() is doing.
This does exactly that. We use __end_rodata_hpage_align as our marker both because it is huge-page-aligned and it does not contain any sections we expect to hold secrets.
Kees's logic was that r/o data is in the kernel image anyway and, in the case of traditional distributions, can be freely downloaded from the web, so there's no reason to hide it.
--- arch/x86/mm/pti.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
arch/x86/mm/pti.c +13 -3
@@ -430,12 +430,24 @@ static inline bool pti_kernel_image_global_ok(void)*/ void pti_clone_kernel_text (void ) { +/* +* rodata is part of the kernel image and is normally +* readable on the filesystem or on the web. But, do not +* clone the areas past rodata, they might contain secrets. +*/ unsigned long start =PFN_ALIGN (_text); -unsigned long end =ALIGN ((unsigned long )_end,PMD_PAGE_SIZE ); +unsigned long end = (unsigned long )__end_rodata_hpage_align;if (!pti_kernel_image_global_ok ())return ; +pr_debug ("mapping partial kernel image into user address space\n" ); + +/* +* Note that this will undo _some_ of the work that +* pti_set_kernel_image_nonglobal() did to clear the +* global bit. +*/ pti_clone_pmds (start, end, _PAGE_RW); }
@@ -458,8 +470,6 @@ void pti_set_kernel_image_nonglobal(void)if (pti_kernel_image_global_ok ())return ; -pr_debug ("set kernel image non-global\n" ); -set_memory_nonglobal (start, (end - start) >>PAGE_SHIFT ); }
Dave Hansen
maintainerPATCH 4/5 x86, pti: disallow global kernel text with RANDSTRUCT
In reply to Dave HansenI believe this was originally reported by the grsecurity team who tweeted about it (link below).
RANDSTRUCT derives its hardening benefits from the attacker's lack of knowledge about the layout of kernel data structures. Keep the kernel image non-global in cases where RANDSTRUCT is in use to help keep the layout a secret.
---
b/arch/x86/mm/pti.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
arch/x86/mm/pti.c renamed from arch/x86/mm/pti.c~pti-glb-disable-with-compile-options +10 -0
@@ -421,6 +421,16 @@ static inline bool pti_kernel_image_globif (boot_cpu_has (X86_FEATURE_K8 ))return false; +/* +* RANDSTRUCT derives its hardening benefits from the +* attacker's lack of knowledge about the layout of kernel +* data structures. Keep the kernel image non-global in +* cases where RANDSTRUCT is in use to help keep the layout a +* secret. +*/ +if (IS_ENABLED (CONFIG_GCC_PLUGIN_RANDSTRUCT )) +return false; +return true; }
_
tip-bot for Dave Hansen
merge bot[tip:x86/pti] x86/pti: Disallow global kernel text with RANDSTRUCT
x86/pti: Disallow global kernel text with RANDSTRUCT
Commit-ID: 26d35ca6c3776784f8156e1d6f80cc60d9a2a915 Gitweb: https://git.kernel.org/tip/26d35ca6c3776784f8156e1d6f80cc60d9a2a915 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 20 Apr 2018 15:20:26 -0700 Committer: Thomas Gleixner <[email protected]> CommitDate: Tue, 24 Apr 2018 09:50:54 +0200
x86/pti: Disallow global kernel text with RANDSTRUCT
RANDSTRUCT derives its hardening benefits from the attacker's lack of knowledge about the layout of kernel data structures. Keep the kernel image non-global in cases where RANDSTRUCT is in use to help keep the layout a secret.
--- arch/x86/mm/pti.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
arch/x86/mm/pti.c +10 -0
@@ -421,6 +421,16 @@ static inline bool pti_kernel_image_global_ok(void)if (boot_cpu_has (X86_FEATURE_K8 ))return false; +/* +* RANDSTRUCT derives its hardening benefits from the +* attacker's lack of knowledge about the layout of kernel +* data structures. Keep the kernel image non-global in +* cases where RANDSTRUCT is in use to help keep the layout a +* secret. +*/ +if (IS_ENABLED (CONFIG_GCC_PLUGIN_RANDSTRUCT )) +return false; +return true; }
tip-bot for Dave Hansen
merge bot[tip:x86/pti] x86/pti: Disallow global kernel text with RANDSTRUCT
In reply to Dave Hansenx86/pti: Disallow global kernel text with RANDSTRUCT
Commit-ID: b7c21bc56fbedf4a61b628c6b11e0d7048746cc1 Gitweb: https://git.kernel.org/tip/b7c21bc56fbedf4a61b628c6b11e0d7048746cc1 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 20 Apr 2018 15:20:26 -0700 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 25 Apr 2018 11:02:51 +0200
x86/pti: Disallow global kernel text with RANDSTRUCT
commit 26d35ca6c3776784f8156e1d6f80cc60d9a2a915
RANDSTRUCT derives its hardening benefits from the attacker's lack of knowledge about the layout of kernel data structures. Keep the kernel image non-global in cases where RANDSTRUCT is in use to help keep the layout a secret.
--- arch/x86/mm/pti.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
arch/x86/mm/pti.c +10 -0
@@ -421,6 +421,16 @@ static inline bool pti_kernel_image_global_ok(void)if (boot_cpu_has (X86_FEATURE_K8 ))return false; +/* +* RANDSTRUCT derives its hardening benefits from the +* attacker's lack of knowledge about the layout of kernel +* data structures. Keep the kernel image non-global in +* cases where RANDSTRUCT is in use to help keep the layout a +* secret. +*/ +if (IS_ENABLED (CONFIG_GCC_PLUGIN_RANDSTRUCT )) +return false; +return true; }
Dave Hansen
maintainerPATCH 5/5 x86, pti: filter at vma->vm_page_prot population
In reply to Dave HansenFrom: Dave Hansen <[email protected]>
0day reported warnings at boot on 32-bit systems without NX support:
[ 12.349193] attempted to set unsupported pgprot: 8000000000000025 bits: 8000000000000000 supported: 7fffffffffffffff [ 12.350792] WARNING: CPU: 0 PID: 1 at arch/x86/include/asm/pgtable.h:540 handle_mm_fault+0xfc1/0xfe0: check_pgprot at arch/x86/include/asm/pgtable.h:535 (inlined by) pfn_pte at arch/x86/include/asm/pgtable.h:549 (inlined by) do_anonymous_page at mm/memory.c:3169 (inlined by) handle_pte_fault at mm/memory.c:3961 (inlined by) __handle_mm_fault at mm/memory.c:4087 (inlined by) handle_mm_fault at mm/memory.c:4124
The problem was that we stopped massaging page permissions at PTE creation time, so vma->vm_page_prot was passed unfiltered to PTE creation.
To fix it, filter the page protections before they are installed in vma->vm_page_prot.
---
b/arch/x86/Kconfig | 4 ++++ b/arch/x86/include/asm/pgtable.h | 5 +++++ b/mm/mmap.c | 11 ++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-)
arch/x86/include/asm/pgtable.h renamed from arch/x86/include/asm/pgtable.h~pti-glb-protection_map +5 -0
@@ -601,6 +601,11 @@ static inline pgprot_t pgprot_modify(pgp#define canon_pgprot (p) __pgprot(massage_pgprot(p)) +static inline pgprot_t arch_filter_pgprot (pgprot_t prot) +{ +return canon_pgprot (prot); +} +static inline int is_new_memtype_allowed (u64 paddr,unsigned long size,enum page_cache_mode pcm,enum page_cache_mode new_pcm)
arch/x86/Kconfig renamed from arch/x86/Kconfig~pti-glb-protection_map +4 -0
@@ -52,6 +52,7 @@ config X86 select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_FAST_MULTIPLIER + select ARCH_HAS_FILTER_PGPROT select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_KCOV if X86_64
@@ -273,6 +274,9 @@ config ARCH_HAS_CPU_RELAX config ARCH_HAS_CACHE_LINE_SIZE def_bool y +config ARCH_HAS_FILTER_PGPROT + def_bool y + config HAVE_SETUP_PER_CPU_AREA def_bool y
mm/mmap.c renamed from mm/mmap.c~pti-glb-protection_map +10 -1
@@ -100,11 +100,20 @@ pgprot_t protection_map[16] __ro_after_i __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 }; +#ifndef CONFIG_ARCH_HAS_FILTER_PGPROT +static inline pgprot_t arch_filter_pgprot (pgprot_t prot) +{ +return prot; +} +#endif +pgprot_t vm_get_page_prot (unsigned long vm_flags) { -return __pgprot (pgprot_val (protection_map[vm_flags & +pgprot_t ret =__pgprot (pgprot_val (protection_map[vm_flags & (VM_READ |VM_WRITE |VM_EXEC |VM_SHARED )]) |pgprot_val (arch_vm_get_page_prot (vm_flags))); + +return arch_filter_pgprot (ret); }EXPORT_SYMBOL (vm_get_page_prot);
_
Re: [PATCH 5/5] x86, pti: filter at vma->vm_page_prot population
Quoted 97 lines · Dave Hansen
From: Dave Hansen <[email protected]>
0day reported warnings at boot on 32-bit systems without NX support:
[ 12.349193] attempted to set unsupported pgprot: 8000000000000025 bits: 8000000000000000 supported: 7fffffffffffffff [ 12.350792] WARNING: CPU: 0 PID: 1 at arch/x86/include/asm/pgtable.h:540 handle_mm_fault+0xfc1/0xfe0: check_pgprot at arch/x86/include/asm/pgtable.h:535 (inlined by) pfn_pte at arch/x86/include/asm/pgtable.h:549 (inlined by) do_anonymous_page at mm/memory.c:3169 (inlined by) handle_pte_fault at mm/memory.c:3961 (inlined by) __handle_mm_fault at mm/memory.c:4087 (inlined by) handle_mm_fault at mm/memory.c:4124The problem was that we stopped massaging page permissions at PTE creation time, so
vma->vm_page_protwas passed unfiltered to PTE creation.To fix it, filter the page protections before they are installed in
vma->vm_page_prot.Signed-off-by Dave Hansen <[email protected]>Reported-by Fengguang Wu <[email protected]>Fixes fb43d6cb91 ("x86/mm: Do not auto-massage page protections")Cc Andrea Arcangeli <[email protected]>Cc Andy Lutomirski <[email protected]>Cc Arjan van de Ven <[email protected]>Cc Borislav Petkov <[email protected]>Cc Dan Williams <[email protected]>Cc David Woodhouse <[email protected]>Cc Greg Kroah-Hartman <[email protected]>Cc Hugh Dickins <[email protected]>Cc Josh Poimboeuf <[email protected]>Cc Juergen Gross <[email protected]>Cc Kees Cook <[email protected]>Cc Linus Torvalds <[email protected]>Cc Nadav Amit <[email protected]>Cc Peter Zijlstra <[email protected]>Cc Thomas Gleixner <[email protected]>Cc Ingo Molnar <[email protected]>---
b/arch/x86/Kconfig | 4 ++++ b/arch/x86/include/asm/pgtable.h | 5 +++++ b/mm/mmap.c | 11 ++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-)diff -puN
arch/x86/include/asm/pgtable.h~pti-glb-protection_maparch/x86/include/asm/pgtable.harch/x86/include/asm/pgtable.h renamed from arch/x86/include/asm/pgtable.h~pti-glb-protection_map +5
-0@@ -601,6 +601,11 @@ static inline pgprot_t pgprot_modify(pgp#define canon_pgprot (p) __pgprot(massage_pgprot(p)) +static inline pgprot_t arch_filter_pgprot (pgprot_t prot) +{ +return canon_pgprot (prot); +} +static inline int is_new_memtype_allowed (u64 paddr,unsigned long size,enum page_cache_mode pcm,enum page_cache_mode new_pcm)diff -puN
arch/x86/Kconfig~pti-glb-protection_maparch/x86/Kconfigarch/x86/Kconfig renamed from arch/x86/Kconfig~pti-glb-protection_map +1
-0@@ -52,6 +52,7 @@ config X86 select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_FAST_MULTIPLIER + select ARCH_HAS_FILTER_PGPROT select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_KCOV if X86_64@@ -273,6 +274,9 @@ config ARCH_HAS_CPU_RELAXconfig
ARCH_HAS_CACHE_LINE_SIZE
def_boolyarch/x86/Kconfig renamed from arch/x86/Kconfig~pti-glb-protection_map +3
-0+config ARCH_HAS_FILTER_PGPROT + def_bool y +config
HAVE_SETUP_PER_CPU_AREA
def_boolydiff -puN
mm/mmap.c~pti-glb-protection_mapmm/mmap.cmm/mmap.c renamed from mm/mmap.c~pti-glb-protection_map +7
-0@@ -100,11 +100,20 @@ pgprot_t protection_map[16] __ro_after_i __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 }; +#ifndef CONFIG_ARCH_HAS_FILTER_PGPROT +static inline pgprot_t arch_filter_pgprot (pgprot_t prot) +{ +return prot; +} +#endif +
mm/mmap.c pgprot_t protection_map[16] __ro_after_i · line 118
Quoted 10 lines
mm/mmap.c renamed from mm/mmap.c~pti-glb-protection_map +3
-1pgprot_t vm_get_page_prot (unsigned long vm_flags) { -return __pgprot (pgprot_val (protection_map[vm_flags & +pgprot_t ret =__pgprot (pgprot_val (protection_map[vm_flags & (VM_READ |VM_WRITE |VM_EXEC |VM_SHARED )]) |pgprot_val (arch_vm_get_page_prot (vm_flags))); + +return arch_filter_pgprot (ret); }EXPORT_SYMBOL (vm_get_page_prot);
Wouldn’t it be simpler or at least cleaner to change the protection map if NX is not supported? I presume it can be done paging_init() similarly to the way other archs (e.g., arm, mips) do.
Dave Hansen
maintainerRe: [PATCH 5/5] x86, pti: filter at vma->vm_page_prot population
Quoted 5 lines · Nadav Amit
Quoted 5 lines
pgprot_tvm_get_page_prot(unsigned long vm_flags)
{mm/mmap.c renamed from mm/mmap.c~pti-glb-protection_map +1
-1- return __pgprot(pgprot_val(protection_map[vm_flags & + pgprot_t ret = __pgprot(pgprot_val(protection_map[vm_flags &(VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]) |
Quoted 8 lines
Quoted 5 lines
pgprot_val(arch_vm_get_page_prot(vm_flags)));(quoted diff) +2
-0+ + return arch_filter_pgprot(ret);}
EXPORT_SYMBOL(vm_get_page_prot);Wouldn’t it be simpler or at least cleaner to change the protection map if NX is not supported? I presume it can be done
paging_init()similarly to the way other archs (e.g., arm, mips) do.
I thought about it, but doing it there requires getting the _timing_ right. You have to do it before the protection map gets used but after __supported_pte_mask is totally initialized. This seemed more straightforward, especially as a bug fix.
What you are talking about might be a good cleanup, though.
tip-bot for Dave Hansen
merge bot[tip:x86/pti] x86, pti: Filter at vma->vm_page_prot population
In reply to Dave Hansenx86, pti: Filter at vma->vm_page_prot population
Commit-ID: ce9962bf7e22bb3891655c349faff618922d4a73 Gitweb: https://git.kernel.org/tip/ce9962bf7e22bb3891655c349faff618922d4a73 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 20 Apr 2018 15:20:28 -0700 Committer: Thomas Gleixner <[email protected]> CommitDate: Tue, 24 Apr 2018 09:50:54 +0200
x86, pti: Filter at vma->vm_page_prot population
0day reported warnings at boot on 32-bit systems without NX support:
attempted to set unsupported pgprot: 8000000000000025 bits: 8000000000000000 supported: 7fffffffffffffff
WARNING: CPU: 0 PID: 1 at arch/x86/include/asm/pgtable.h:540 handle_mm_fault+0xfc1/0xfe0: check_pgprot at arch/x86/include/asm/pgtable.h:535 (inlined by) pfn_pte at arch/x86/include/asm/pgtable.h:549 (inlined by) do_anonymous_page at mm/memory.c:3169 (inlined by) handle_pte_fault at mm/memory.c:3961 (inlined by) __handle_mm_fault at mm/memory.c:4087 (inlined by) handle_mm_fault at mm/memory.c:4124
The problem is that due to the recent commit which removed auto-massaging of page protections, filtering page permissions at PTE creation time is not longer done, so vma->vm_page_prot is passed unfiltered to PTE creation.
Filter the page protections before they are installed in vma->vm_page_prot.
--- arch/x86/Kconfig | 4 ++++ arch/x86/include/asm/pgtable.h | 5 +++++ mm/mmap.c | 11 ++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-)
arch/x86/Kconfig +4 -0
@@ -52,6 +52,7 @@ config X86 select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_FAST_MULTIPLIER + select ARCH_HAS_FILTER_PGPROT select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_KCOV if X86_64
@@ -273,6 +274,9 @@ config ARCH_HAS_CPU_RELAX config ARCH_HAS_CACHE_LINE_SIZE def_bool y +config ARCH_HAS_FILTER_PGPROT + def_bool y + config HAVE_SETUP_PER_CPU_AREA def_bool y
arch/x86/include/asm/pgtable.h +5 -0
@@ -601,6 +601,11 @@ static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)#define canon_pgprot (p) __pgprot(massage_pgprot(p)) +static inline pgprot_t arch_filter_pgprot (pgprot_t prot) +{ +return canon_pgprot (prot); +} +static inline int is_new_memtype_allowed (u64 paddr,unsigned long size,enum page_cache_mode pcm,enum page_cache_mode new_pcm)
mm/mmap.c +10 -1
@@ -100,11 +100,20 @@ pgprot_t protection_map[16] __ro_after_init = { __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 }; +#ifndef CONFIG_ARCH_HAS_FILTER_PGPROT +static inline pgprot_t arch_filter_pgprot (pgprot_t prot) +{ +return prot; +} +#endif +pgprot_t vm_get_page_prot (unsigned long vm_flags) { -return __pgprot (pgprot_val (protection_map[vm_flags & +pgprot_t ret =__pgprot (pgprot_val (protection_map[vm_flags & (VM_READ |VM_WRITE |VM_EXEC |VM_SHARED )]) |pgprot_val (arch_vm_get_page_prot (vm_flags))); + +return arch_filter_pgprot (ret); }EXPORT_SYMBOL (vm_get_page_prot);
tip-bot for Dave Hansen
merge bot[tip:x86/pti] x86/pti: Filter at vma->vm_page_prot population
In reply to Dave Hansenx86/pti: Filter at vma->vm_page_prot population
Commit-ID: 316d097c4cd4e7f2ef50c40cff2db266593c4ec4 Gitweb: https://git.kernel.org/tip/316d097c4cd4e7f2ef50c40cff2db266593c4ec4 Author: Dave Hansen <[email protected]> AuthorDate: Fri, 20 Apr 2018 15:20:28 -0700 Committer: Thomas Gleixner <[email protected]> CommitDate: Wed, 25 Apr 2018 11:02:51 +0200
x86/pti: Filter at vma->vm_page_prot population
commit ce9962bf7e22bb3891655c349faff618922d4a73
0day reported warnings at boot on 32-bit systems without NX support:
attempted to set unsupported pgprot: 8000000000000025 bits: 8000000000000000 supported: 7fffffffffffffff
WARNING: CPU: 0 PID: 1 at arch/x86/include/asm/pgtable.h:540 handle_mm_fault+0xfc1/0xfe0: check_pgprot at arch/x86/include/asm/pgtable.h:535 (inlined by) pfn_pte at arch/x86/include/asm/pgtable.h:549 (inlined by) do_anonymous_page at mm/memory.c:3169 (inlined by) handle_pte_fault at mm/memory.c:3961 (inlined by) __handle_mm_fault at mm/memory.c:4087 (inlined by) handle_mm_fault at mm/memory.c:4124
The problem is that due to the recent commit which removed auto-massaging of page protections, filtering page permissions at PTE creation time is not longer done, so vma->vm_page_prot is passed unfiltered to PTE creation.
Filter the page protections before they are installed in vma->vm_page_prot.
--- arch/x86/Kconfig | 4 ++++ arch/x86/include/asm/pgtable.h | 5 +++++ mm/mmap.c | 11 ++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-)
arch/x86/Kconfig +4 -0
@@ -52,6 +52,7 @@ config X86 select ARCH_HAS_DEVMEM_IS_ALLOWED select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_FAST_MULTIPLIER + select ARCH_HAS_FILTER_PGPROT select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_KCOV if X86_64
@@ -273,6 +274,9 @@ config ARCH_HAS_CPU_RELAX config ARCH_HAS_CACHE_LINE_SIZE def_bool y +config ARCH_HAS_FILTER_PGPROT + def_bool y + config HAVE_SETUP_PER_CPU_AREA def_bool y
arch/x86/include/asm/pgtable.h +5 -0
@@ -601,6 +601,11 @@ static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)#define canon_pgprot (p) __pgprot(massage_pgprot(p)) +static inline pgprot_t arch_filter_pgprot (pgprot_t prot) +{ +return canon_pgprot (prot); +} +static inline int is_new_memtype_allowed (u64 paddr,unsigned long size,enum page_cache_mode pcm,enum page_cache_mode new_pcm)
mm/mmap.c +10 -1
@@ -100,11 +100,20 @@ pgprot_t protection_map[16] __ro_after_init = { __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 }; +#ifndef CONFIG_ARCH_HAS_FILTER_PGPROT +static inline pgprot_t arch_filter_pgprot (pgprot_t prot) +{ +return prot; +} +#endif +pgprot_t vm_get_page_prot (unsigned long vm_flags) { -return __pgprot (pgprot_val (protection_map[vm_flags & +pgprot_t ret =__pgprot (pgprot_val (protection_map[vm_flags & (VM_READ |VM_WRITE |VM_EXEC |VM_SHARED )]) |pgprot_val (arch_vm_get_page_prot (vm_flags))); + +return arch_filter_pgprot (ret); }EXPORT_SYMBOL (vm_get_page_prot);