From: Dave Hansen <dave.hansen@linux.intel.com>
To: linux-kernel@vger.kernel.org
Cc: Dave Hansen <dave.hansen@linux.intel.com>,
aarcange@redhat.com, luto@kernel.org,
torvalds@linux-foundation.org, keescook@google.com,
hughd@google.com, jgross@suse.com, x86@kernel.org,
namit@vmware.com
Subject: [RFC][PATCH 05/10] x86/mm: do not auto-massage page protections
Date: Thu, 22 Feb 2018 12:37:00 -0800 [thread overview]
Message-ID: <20180222203700.3FDE6BFD@viggo.jf.intel.com> (raw)
In-Reply-To: <20180222203651.B776810C@viggo.jf.intel.com>
From: Dave Hansen <dave.hansen@linux.intel.com>
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 <dave.hansen@linux.intel.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Kees Cook <keescook@google.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: x86@kernel.org
Cc: Nadav Amit <namit@vmware.com>
---
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-massage 2018-02-22 12:36:19.752036551 -0800
+++ b/arch/x86/include/asm/pgtable.h 2018-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
* permission check.
*/
- pte = pfn_pte(pfn, __pgprot(__PAGE_KERNEL_RO & ~_PAGE_GLOBAL));
+ pte_prot = __pgprot(__PAGE_KERNEL_RO & ~_PAGE_GLOBAL);
+ /* Filter out unsuppored __PAGE_KERNEL* bits: */
+ pgprot_val(pte_prot) |= __supported_pte_mask;
+ pte = pfn_pte(pfn, pte_prot);
set_pte_at(mm, va, ptep, pte);
pte_unmap_unlock(ptep, ptl);
}
diff -puN arch/x86/mm/ident_map.c~x86-no-auto-massage arch/x86/mm/ident_map.c
--- a/arch/x86/mm/ident_map.c~x86-no-auto-massage 2018-02-22 12:36:19.758036551 -0800
+++ b/arch/x86/mm/ident_map.c 2018-02-22 12:36:19.769036551 -0800
@@ -98,6 +98,9 @@ int kernel_ident_mapping_init(struct x86
if (!info->kernpg_flag)
info->kernpg_flag = _KERNPG_TABLE;
+ /* Filter out unsupported __PAGE_KERNEL_* bits: */
+ info->kernpg_flag &= __default_kernel_pte_mask;
+
for (; addr < end; addr = next) {
pgd_t *pgd = pgd_page + pgd_index(addr);
p4d_t *p4d;
diff -puN arch/x86/mm/iomap_32.c~x86-no-auto-massage arch/x86/mm/iomap_32.c
--- a/arch/x86/mm/iomap_32.c~x86-no-auto-massage 2018-02-22 12:36:19.760036551 -0800
+++ b/arch/x86/mm/iomap_32.c 2018-02-22 12:36:19.770036551 -0800
@@ -44,6 +44,9 @@ int iomap_create_wc(resource_size_t base
return ret;
*prot = __pgprot(__PAGE_KERNEL | cachemode2protval(pcm));
+ /* Filter out unsupported __PAGE_KERNEL* bits: */
+ pgprot_val(*prot) &= __default_kernel_pte_mask;
+
return 0;
}
EXPORT_SYMBOL_GPL(iomap_create_wc);
@@ -88,6 +91,9 @@ iomap_atomic_prot_pfn(unsigned long pfn,
prot = __pgprot(__PAGE_KERNEL |
cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS));
+ /* Filter out unsupported __PAGE_KERNEL* bits: */
+ pgprot_val(prot) &= __default_kernel_pte_mask;
+
return (void __force __iomem *) kmap_atomic_prot_pfn(pfn, prot);
}
EXPORT_SYMBOL_GPL(iomap_atomic_prot_pfn);
diff -puN arch/x86/mm/kasan_init_64.c~x86-no-auto-massage arch/x86/mm/kasan_init_64.c
--- a/arch/x86/mm/kasan_init_64.c~x86-no-auto-massage 2018-02-22 12:36:19.761036551 -0800
+++ b/arch/x86/mm/kasan_init_64.c 2018-02-22 12:36:19.770036551 -0800
@@ -263,6 +263,12 @@ void __init kasan_early_init(void)
pudval_t pud_val = __pa_nodebug(kasan_zero_pmd) | _KERNPG_TABLE;
p4dval_t p4d_val = __pa_nodebug(kasan_zero_pud) | _KERNPG_TABLE;
+ /* Mask out unsupported __PAGE_KERNEL bits: */
+ pte_val &= __default_kernel_pte_mask;
+ pmd_val &= __default_kernel_pte_mask;
+ pud_val &= __default_kernel_pte_mask;
+ p4d_val &= __default_kernel_pte_mask;
+
for (i = 0; i < PTRS_PER_PTE; i++)
kasan_zero_pte[i] = __pte(pte_val);
@@ -365,7 +371,13 @@ void __init kasan_init(void)
*/
memset(kasan_zero_page, 0, PAGE_SIZE);
for (i = 0; i < PTRS_PER_PTE; i++) {
- pte_t pte = __pte(__pa(kasan_zero_page) | __PAGE_KERNEL_RO | _PAGE_ENC);
+ pte_t pte;
+ pgprot_t prot;
+
+ prot = __pgprot(__PAGE_KERNEL_RO | _PAGE_ENC);
+ pgprot_val(prot) &= __default_kernel_pte_mask;
+
+ pte = __pte(__pa(kasan_zero_page) | pgprot_val(prot));
set_pte(&kasan_zero_pte[i], pte);
}
/* Flush TLBs again to be sure that write protection applied. */
diff -puN arch/x86/power/hibernate_64.c~x86-no-auto-massage arch/x86/power/hibernate_64.c
--- a/arch/x86/power/hibernate_64.c~x86-no-auto-massage 2018-02-22 12:36:19.763036551 -0800
+++ b/arch/x86/power/hibernate_64.c 2018-02-22 12:36:19.770036551 -0800
@@ -51,6 +51,12 @@ static int set_up_temporary_text_mapping
pmd_t *pmd;
pud_t *pud;
p4d_t *p4d;
+ pgprot_t pgtable_prot = __pgprot(_KERNPG_TABLE);
+ pgprot_t pmd_text_prot = __pgprot(__PAGE_KERNEL_LARGE_EXEC);
+
+ /* Filter out unsupported __PAGE_KERNEL* bits: */
+ pgprot_val(pmd_text_prot) &= __default_kernel_pte_mask;
+ pgprot_val(pgtable_prot) &= __default_kernel_pte_mask;
/*
* The new mapping only has to cover the page containing the image
@@ -81,15 +87,19 @@ static int set_up_temporary_text_mapping
return -ENOMEM;
set_pmd(pmd + pmd_index(restore_jump_address),
- __pmd((jump_address_phys & PMD_MASK) | __PAGE_KERNEL_LARGE_EXEC));
+ __pmd((jump_address_phys & PMD_MASK) | pgprot_val(pmd_text_prot)));
set_pud(pud + pud_index(restore_jump_address),
- __pud(__pa(pmd) | _KERNPG_TABLE));
+ __pud(__pa(pmd) | pgprot_val(pgtable_prot)));
if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
- set_p4d(p4d + p4d_index(restore_jump_address), __p4d(__pa(pud) | _KERNPG_TABLE));
- set_pgd(pgd + pgd_index(restore_jump_address), __pgd(__pa(p4d) | _KERNPG_TABLE));
+ p4d_t new_p4d = __p4d(__pa(pud) | pgprot_val(pgtable_prot));
+ pgd_t new_pgd = __pgd(__pa(p4d) | pgprot_val(pgtable_prot));
+
+ set_p4d(p4d + p4d_index(restore_jump_address), new_p4d);
+ set_pgd(pgd + pgd_index(restore_jump_address), new_pgd);
} else {
/* No p4d for 4-level paging: point the pgd to the pud page table */
- set_pgd(pgd + pgd_index(restore_jump_address), __pgd(__pa(pud) | _KERNPG_TABLE));
+ pgd_t new_pgd = __pgd(__pa(p4d) | pgprot_val(pgtable_prot));
+ set_pgd(pgd + pgd_index(restore_jump_address), new_pgd);
}
return 0;
diff -puN mm/early_ioremap.c~x86-no-auto-massage mm/early_ioremap.c
--- a/mm/early_ioremap.c~x86-no-auto-massage 2018-02-22 12:36:19.765036551 -0800
+++ b/mm/early_ioremap.c 2018-02-22 12:36:19.770036551 -0800
@@ -113,6 +113,9 @@ __early_ioremap(resource_size_t phys_add
WARN_ON(system_state >= SYSTEM_RUNNING);
+ /* Sanitize 'prot' against any unsupported bits: */
+ pgprot_val(prot) &= __default_kernel_pte_mask;
+
slot = -1;
for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
if (!prev_map[i]) {
_
next prev parent reply other threads:[~2018-02-22 20:39 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-02-22 20:36 [RFC][PATCH 00/10] Use global pages with PTI Dave Hansen
2018-02-22 20:36 ` [RFC][PATCH 01/10] x86/mm: factor out pageattr _PAGE_GLOBAL setting Dave Hansen
2018-02-22 20:36 ` [RFC][PATCH 02/10] x86/mm: undo double _PAGE_PSE clearing Dave Hansen
2018-02-22 20:36 ` [RFC][PATCH 03/10] x86/mm: introduce "default" kernel PTE mask Dave Hansen
2018-02-22 22:21 ` Nadav Amit
2018-02-22 22:26 ` Dave Hansen
2018-02-22 23:11 ` Tom Lendacky
2018-02-23 23:46 ` Dave Hansen
2018-02-22 20:36 ` [RFC][PATCH 04/10] x86/espfix: use kernel-default " Dave Hansen
2018-02-22 21:27 ` Nadav Amit
2018-02-22 21:30 ` Dave Hansen
2018-02-22 21:59 ` Andy Lutomirski
2018-02-22 22:05 ` Dave Hansen
2018-02-22 20:37 ` Dave Hansen [this message]
2018-02-22 21:46 ` [RFC][PATCH 05/10] x86/mm: do not auto-massage page protections Nadav Amit
2018-02-22 21:52 ` Dave Hansen
2018-02-22 20:37 ` [RFC][PATCH 06/10] x86/mm: remove extra filtering in pageattr code Dave Hansen
2018-02-22 20:37 ` [RFC][PATCH 07/10] x86/mm: comment _PAGE_GLOBAL mystery Dave Hansen
2018-02-22 20:37 ` [RFC][PATCH 08/10] x86/mm: do not forbid _PAGE_RW before init for __ro_after_init Dave Hansen
2018-02-22 20:53 ` Kees Cook
2018-02-22 20:37 ` [RFC][PATCH 09/10] x86/pti: enable global pages for shared areas Dave Hansen
2018-02-22 20:37 ` [RFC][PATCH 10/10] x86/pti: clear _PAGE_GLOBAL for kernel image Dave Hansen
2018-02-22 21:52 ` [RFC][PATCH 00/10] Use global pages with PTI Linus Torvalds
2018-02-24 1:49 ` Dave Hansen
2018-02-24 4:20 ` Linus Torvalds
2018-02-24 4:34 ` [RFC][PATCH 00/10] Use global pages with PTI - Truth about the white man thetruthbeforeus
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180222203700.3FDE6BFD@viggo.jf.intel.com \
--to=dave.hansen@linux.intel.com \
--cc=aarcange@redhat.com \
--cc=hughd@google.com \
--cc=jgross@suse.com \
--cc=keescook@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=luto@kernel.org \
--cc=namit@vmware.com \
--cc=torvalds@linux-foundation.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox