Re: [RFC][PATCH 05/10] x86/mm: do not auto-massage page protections

2018-02-22 Thread Dave Hansen
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

2018-02-22 Thread Dave Hansen
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

2018-02-22 Thread Nadav Amit
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?



Re: [RFC][PATCH 05/10] x86/mm: do not auto-massage page protections

2018-02-22 Thread Nadav Amit
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

2018-02-22 Thread Dave Hansen

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, 

[RFC][PATCH 05/10] x86/mm: do not auto-massage page protections

2018-02-22 Thread Dave Hansen

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