Re: [RFC][PATCH 05/10] x86/mm: do not auto-massage page protections
On 02/22/2018 01:46 PM, Nadav Amit wrote: >> >> +static inline pgprotval_t check_pgprot(pgprot_t pgprot) >> +{ >> +pgprotval_t massaged_val = massage_pgprot(pgprot); >> + >> +WARN_ONCE(pgprot_val(pgprot) != massaged_val, >> + "attempted to set unsupported pgprot: %016lx " >> + "bits: %016lx supported: %016lx\n", >> + pgprot_val(pgprot), >> + pgprot_val(pgprot) ^ massaged_val, >> + __supported_pte_mask); > Perhaps use VM_WARN_ONCE instead to avoid any overhead on production > systems? Sounds sane enough. I'll change it.
Re: [RFC][PATCH 05/10] x86/mm: do not auto-massage page protections
On 02/22/2018 01:46 PM, Nadav Amit wrote: >> >> +static inline pgprotval_t check_pgprot(pgprot_t pgprot) >> +{ >> +pgprotval_t massaged_val = massage_pgprot(pgprot); >> + >> +WARN_ONCE(pgprot_val(pgprot) != massaged_val, >> + "attempted to set unsupported pgprot: %016lx " >> + "bits: %016lx supported: %016lx\n", >> + pgprot_val(pgprot), >> + pgprot_val(pgprot) ^ massaged_val, >> + __supported_pte_mask); > Perhaps use VM_WARN_ONCE instead to avoid any overhead on production > systems? Sounds sane enough. I'll change it.
Re: [RFC][PATCH 05/10] x86/mm: do not auto-massage page protections
Dave Hansenwrote: > > From: Dave Hansen > > > +static inline pgprotval_t check_pgprot(pgprot_t pgprot) > +{ > + pgprotval_t massaged_val = massage_pgprot(pgprot); > + > + WARN_ONCE(pgprot_val(pgprot) != massaged_val, > + "attempted to set unsupported pgprot: %016lx " > + "bits: %016lx supported: %016lx\n", > + pgprot_val(pgprot), > + pgprot_val(pgprot) ^ massaged_val, > + __supported_pte_mask); Perhaps use VM_WARN_ONCE instead to avoid any overhead on production systems?
Re: [RFC][PATCH 05/10] x86/mm: do not auto-massage page protections
Dave Hansen wrote: > > From: Dave Hansen > > > +static inline pgprotval_t check_pgprot(pgprot_t pgprot) > +{ > + pgprotval_t massaged_val = massage_pgprot(pgprot); > + > + WARN_ONCE(pgprot_val(pgprot) != massaged_val, > + "attempted to set unsupported pgprot: %016lx " > + "bits: %016lx supported: %016lx\n", > + pgprot_val(pgprot), > + pgprot_val(pgprot) ^ massaged_val, > + __supported_pte_mask); Perhaps use VM_WARN_ONCE instead to avoid any overhead on production systems?
[RFC][PATCH 05/10] x86/mm: do not auto-massage page protections
From: Dave HansenA 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 set_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 set_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. Signed-off-by: Dave Hansen Cc: Andrea Arcangeli Cc: Andy Lutomirski Cc: Linus Torvalds Cc: Kees Cook Cc: Hugh Dickins Cc: Juergen Gross Cc: x...@kernel.org Cc: Nadav Amit --- b/arch/x86/include/asm/pgtable.h | 24 +++- b/arch/x86/kernel/head64.c |2 ++ b/arch/x86/kernel/ldt.c |6 +- b/arch/x86/mm/ident_map.c|3 +++ b/arch/x86/mm/iomap_32.c |6 ++ b/arch/x86/mm/kasan_init_64.c| 14 +- b/arch/x86/power/hibernate_64.c | 20 +++- b/mm/early_ioremap.c |3 +++ 8 files changed, 66 insertions(+), 12 deletions(-) diff -puN arch/x86/include/asm/pgtable.h~x86-no-auto-massage arch/x86/include/asm/pgtable.h --- a/arch/x86/include/asm/pgtable.h~x86-no-auto-massage2018-02-22 12:36:19.752036551 -0800 +++ b/arch/x86/include/asm/pgtable.h2018-02-22 12:36:19.769036551 -0800 @@ -526,22 +526,36 @@ static inline pgprotval_t massage_pgprot return protval; } +static inline pgprotval_t check_pgprot(pgprot_t pgprot) +{ + pgprotval_t massaged_val = massage_pgprot(pgprot); + + WARN_ONCE(pgprot_val(pgprot) != massaged_val, + "attempted to set unsupported pgprot: %016lx " + "bits: %016lx supported: %016lx\n", + pgprot_val(pgprot), + pgprot_val(pgprot) ^ massaged_val, + __supported_pte_mask); + + return massaged_val; +} + static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot) { return __pte(((phys_addr_t)page_nr << PAGE_SHIFT) | -massage_pgprot(pgprot)); +check_pgprot(pgprot)); } static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) { return __pmd(((phys_addr_t)page_nr << PAGE_SHIFT) | -massage_pgprot(pgprot)); +check_pgprot(pgprot)); } static inline pud_t pfn_pud(unsigned long page_nr, pgprot_t pgprot) { return __pud(((phys_addr_t)page_nr << PAGE_SHIFT) | -massage_pgprot(pgprot)); +check_pgprot(pgprot)); } static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) @@ -553,7 +567,7 @@ static inline pte_t pte_modify(pte_t pte * the newprot (if present): */ val &= _PAGE_CHG_MASK; - val |= massage_pgprot(newprot) & ~_PAGE_CHG_MASK; + val |= check_pgprot(newprot) & ~_PAGE_CHG_MASK; return __pte(val); } @@ -563,7 +577,7 @@ static inline pmd_t pmd_modify(pmd_t pmd pmdval_t val = pmd_val(pmd); val &= _HPAGE_CHG_MASK; - val |= massage_pgprot(newprot) & ~_HPAGE_CHG_MASK; + val |= check_pgprot(newprot) & ~_HPAGE_CHG_MASK; return __pmd(val); } diff -puN arch/x86/kernel/head64.c~x86-no-auto-massage arch/x86/kernel/head64.c --- a/arch/x86/kernel/head64.c~x86-no-auto-massage 2018-02-22 12:36:19.754036551 -0800 +++ b/arch/x86/kernel/head64.c 2018-02-22 12:36:19.769036551 -0800 @@ -129,6 +129,8 @@ unsigned long __head __startup_64(unsign pud[i + 1] = (pudval_t)pmd + pgtable_flags; pmd_entry = __PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL; + /* Filter out unsupported __PAGE_KERNEL_* bits: */ + pmd_entry |= __supported_pte_mask; pmd_entry += sme_get_me_mask(); pmd_entry += physaddr; diff -puN arch/x86/kernel/ldt.c~x86-no-auto-massage arch/x86/kernel/ldt.c --- a/arch/x86/kernel/ldt.c~x86-no-auto-massage 2018-02-22 12:36:19.756036551 -0800 +++ b/arch/x86/kernel/ldt.c 2018-02-22 12:36:19.769036551 -0800 @@ -145,6 +145,7 @@ map_ldt_struct(struct mm_struct *mm, str unsigned long offset = i << PAGE_SHIFT; const void *src = (char *)ldt->entries + offset; unsigned long pfn; + pgprot_t pte_prot; pte_t pte,
[RFC][PATCH 05/10] x86/mm: do not auto-massage page protections
From: Dave Hansen 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 set_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 set_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. Signed-off-by: Dave Hansen Cc: Andrea Arcangeli Cc: Andy Lutomirski Cc: Linus Torvalds Cc: Kees Cook Cc: Hugh Dickins Cc: Juergen Gross Cc: x...@kernel.org Cc: Nadav Amit --- b/arch/x86/include/asm/pgtable.h | 24 +++- b/arch/x86/kernel/head64.c |2 ++ b/arch/x86/kernel/ldt.c |6 +- b/arch/x86/mm/ident_map.c|3 +++ b/arch/x86/mm/iomap_32.c |6 ++ b/arch/x86/mm/kasan_init_64.c| 14 +- b/arch/x86/power/hibernate_64.c | 20 +++- b/mm/early_ioremap.c |3 +++ 8 files changed, 66 insertions(+), 12 deletions(-) diff -puN arch/x86/include/asm/pgtable.h~x86-no-auto-massage arch/x86/include/asm/pgtable.h --- a/arch/x86/include/asm/pgtable.h~x86-no-auto-massage2018-02-22 12:36:19.752036551 -0800 +++ b/arch/x86/include/asm/pgtable.h2018-02-22 12:36:19.769036551 -0800 @@ -526,22 +526,36 @@ static inline pgprotval_t massage_pgprot return protval; } +static inline pgprotval_t check_pgprot(pgprot_t pgprot) +{ + pgprotval_t massaged_val = massage_pgprot(pgprot); + + WARN_ONCE(pgprot_val(pgprot) != massaged_val, + "attempted to set unsupported pgprot: %016lx " + "bits: %016lx supported: %016lx\n", + pgprot_val(pgprot), + pgprot_val(pgprot) ^ massaged_val, + __supported_pte_mask); + + return massaged_val; +} + static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot) { return __pte(((phys_addr_t)page_nr << PAGE_SHIFT) | -massage_pgprot(pgprot)); +check_pgprot(pgprot)); } static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) { return __pmd(((phys_addr_t)page_nr << PAGE_SHIFT) | -massage_pgprot(pgprot)); +check_pgprot(pgprot)); } static inline pud_t pfn_pud(unsigned long page_nr, pgprot_t pgprot) { return __pud(((phys_addr_t)page_nr << PAGE_SHIFT) | -massage_pgprot(pgprot)); +check_pgprot(pgprot)); } static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) @@ -553,7 +567,7 @@ static inline pte_t pte_modify(pte_t pte * the newprot (if present): */ val &= _PAGE_CHG_MASK; - val |= massage_pgprot(newprot) & ~_PAGE_CHG_MASK; + val |= check_pgprot(newprot) & ~_PAGE_CHG_MASK; return __pte(val); } @@ -563,7 +577,7 @@ static inline pmd_t pmd_modify(pmd_t pmd pmdval_t val = pmd_val(pmd); val &= _HPAGE_CHG_MASK; - val |= massage_pgprot(newprot) & ~_HPAGE_CHG_MASK; + val |= check_pgprot(newprot) & ~_HPAGE_CHG_MASK; return __pmd(val); } diff -puN arch/x86/kernel/head64.c~x86-no-auto-massage arch/x86/kernel/head64.c --- a/arch/x86/kernel/head64.c~x86-no-auto-massage 2018-02-22 12:36:19.754036551 -0800 +++ b/arch/x86/kernel/head64.c 2018-02-22 12:36:19.769036551 -0800 @@ -129,6 +129,8 @@ unsigned long __head __startup_64(unsign pud[i + 1] = (pudval_t)pmd + pgtable_flags; pmd_entry = __PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL; + /* Filter out unsupported __PAGE_KERNEL_* bits: */ + pmd_entry |= __supported_pte_mask; pmd_entry += sme_get_me_mask(); pmd_entry += physaddr; diff -puN arch/x86/kernel/ldt.c~x86-no-auto-massage arch/x86/kernel/ldt.c --- a/arch/x86/kernel/ldt.c~x86-no-auto-massage 2018-02-22 12:36:19.756036551 -0800 +++ b/arch/x86/kernel/ldt.c 2018-02-22 12:36:19.769036551 -0800 @@ -145,6 +145,7 @@ map_ldt_struct(struct mm_struct *mm, str unsigned long offset = i << PAGE_SHIFT; const void *src = (char *)ldt->entries + offset; unsigned long pfn; + pgprot_t pte_prot; pte_t pte, *ptep; va = (unsigned long)ldt_slot_va(slot) + offset; @@ -163,7 +164,10 @@ map_ldt_struct(struct mm_struct *mm, str * target via some kernel interface which misses a