245 lines
8.0 KiB
Diff
245 lines
8.0 KiB
Diff
From f6bb8e560b2229af5dcf3127fc92e732539b4823 Mon Sep 17 00:00:00 2001
|
|
From: Andrey Ryabinin <aryabinin@virtuozzo.com>
|
|
Date: Fri, 29 Sep 2017 17:08:18 +0300
|
|
Subject: [PATCH 075/232] x86/kasan: Use the same shadow offset for 4- and
|
|
5-level paging
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
CVE-2017-5754
|
|
|
|
We are going to support boot-time switching between 4- and 5-level
|
|
paging. For KASAN it means we cannot have different KASAN_SHADOW_OFFSET
|
|
for different paging modes: the constant is passed to gcc to generate
|
|
code and cannot be changed at runtime.
|
|
|
|
This patch changes KASAN code to use 0xdffffc0000000000 as shadow offset
|
|
for both 4- and 5-level paging.
|
|
|
|
For 5-level paging it means that shadow memory region is not aligned to
|
|
PGD boundary anymore and we have to handle unaligned parts of the region
|
|
properly.
|
|
|
|
In addition, we have to exclude paravirt code from KASAN instrumentation
|
|
as we now use set_pgd() before KASAN is fully ready.
|
|
|
|
[kirill.shutemov@linux.intel.com: clenaup, changelog message]
|
|
Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
|
|
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
|
|
Cc: Andrew Morton <akpm@linux-foundation.org>
|
|
Cc: Andy Lutomirski <luto@amacapital.net>
|
|
Cc: Borislav Petkov <bp@suse.de>
|
|
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
|
|
Cc: Linus Torvalds <torvalds@linux-foundation.org>
|
|
Cc: Peter Zijlstra <peterz@infradead.org>
|
|
Cc: Thomas Gleixner <tglx@linutronix.de>
|
|
Cc: linux-mm@kvack.org
|
|
Link: http://lkml.kernel.org/r/20170929140821.37654-4-kirill.shutemov@linux.intel.com
|
|
Signed-off-by: Ingo Molnar <mingo@kernel.org>
|
|
(cherry picked from commit 12a8cc7fcf54a8575f094be1e99032ec38aa045c)
|
|
Signed-off-by: Andy Whitcroft <apw@canonical.com>
|
|
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
|
|
(cherry picked from commit 2ce428150e002623aa0ed2a1ab840fde5f860f32)
|
|
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
|
|
---
|
|
Documentation/x86/x86_64/mm.txt | 2 +-
|
|
arch/x86/kernel/Makefile | 3 +-
|
|
arch/x86/mm/kasan_init_64.c | 101 +++++++++++++++++++++++++++++++---------
|
|
arch/x86/Kconfig | 1 -
|
|
4 files changed, 83 insertions(+), 24 deletions(-)
|
|
|
|
diff --git a/Documentation/x86/x86_64/mm.txt b/Documentation/x86/x86_64/mm.txt
|
|
index b0798e281aa6..3448e675b462 100644
|
|
--- a/Documentation/x86/x86_64/mm.txt
|
|
+++ b/Documentation/x86/x86_64/mm.txt
|
|
@@ -34,7 +34,7 @@ ff92000000000000 - ffd1ffffffffffff (=54 bits) vmalloc/ioremap space
|
|
ffd2000000000000 - ffd3ffffffffffff (=49 bits) hole
|
|
ffd4000000000000 - ffd5ffffffffffff (=49 bits) virtual memory map (512TB)
|
|
... unused hole ...
|
|
-ffd8000000000000 - fff7ffffffffffff (=53 bits) kasan shadow memory (8PB)
|
|
+ffdf000000000000 - fffffc0000000000 (=53 bits) kasan shadow memory (8PB)
|
|
... unused hole ...
|
|
ffffff0000000000 - ffffff7fffffffff (=39 bits) %esp fixup stacks
|
|
... unused hole ...
|
|
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
|
|
index 5bf0d5a473b4..aa059806201d 100644
|
|
--- a/arch/x86/kernel/Makefile
|
|
+++ b/arch/x86/kernel/Makefile
|
|
@@ -24,7 +24,8 @@ endif
|
|
KASAN_SANITIZE_head$(BITS).o := n
|
|
KASAN_SANITIZE_dumpstack.o := n
|
|
KASAN_SANITIZE_dumpstack_$(BITS).o := n
|
|
-KASAN_SANITIZE_stacktrace.o := n
|
|
+KASAN_SANITIZE_stacktrace.o := n
|
|
+KASAN_SANITIZE_paravirt.o := n
|
|
|
|
OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o := y
|
|
OBJECT_FILES_NON_STANDARD_ftrace_$(BITS).o := y
|
|
diff --git a/arch/x86/mm/kasan_init_64.c b/arch/x86/mm/kasan_init_64.c
|
|
index 02c9d7553409..464089f33e80 100644
|
|
--- a/arch/x86/mm/kasan_init_64.c
|
|
+++ b/arch/x86/mm/kasan_init_64.c
|
|
@@ -15,6 +15,8 @@
|
|
extern pgd_t early_top_pgt[PTRS_PER_PGD];
|
|
extern struct range pfn_mapped[E820_MAX_ENTRIES];
|
|
|
|
+static p4d_t tmp_p4d_table[PTRS_PER_P4D] __initdata __aligned(PAGE_SIZE);
|
|
+
|
|
static int __init map_range(struct range *range)
|
|
{
|
|
unsigned long start;
|
|
@@ -30,8 +32,10 @@ static void __init clear_pgds(unsigned long start,
|
|
unsigned long end)
|
|
{
|
|
pgd_t *pgd;
|
|
+ /* See comment in kasan_init() */
|
|
+ unsigned long pgd_end = end & PGDIR_MASK;
|
|
|
|
- for (; start < end; start += PGDIR_SIZE) {
|
|
+ for (; start < pgd_end; start += PGDIR_SIZE) {
|
|
pgd = pgd_offset_k(start);
|
|
/*
|
|
* With folded p4d, pgd_clear() is nop, use p4d_clear()
|
|
@@ -42,29 +46,61 @@ static void __init clear_pgds(unsigned long start,
|
|
else
|
|
pgd_clear(pgd);
|
|
}
|
|
+
|
|
+ pgd = pgd_offset_k(start);
|
|
+ for (; start < end; start += P4D_SIZE)
|
|
+ p4d_clear(p4d_offset(pgd, start));
|
|
+}
|
|
+
|
|
+static inline p4d_t *early_p4d_offset(pgd_t *pgd, unsigned long addr)
|
|
+{
|
|
+ unsigned long p4d;
|
|
+
|
|
+ if (!IS_ENABLED(CONFIG_X86_5LEVEL))
|
|
+ return (p4d_t *)pgd;
|
|
+
|
|
+ p4d = __pa_nodebug(pgd_val(*pgd)) & PTE_PFN_MASK;
|
|
+ p4d += __START_KERNEL_map - phys_base;
|
|
+ return (p4d_t *)p4d + p4d_index(addr);
|
|
+}
|
|
+
|
|
+static void __init kasan_early_p4d_populate(pgd_t *pgd,
|
|
+ unsigned long addr,
|
|
+ unsigned long end)
|
|
+{
|
|
+ pgd_t pgd_entry;
|
|
+ p4d_t *p4d, p4d_entry;
|
|
+ unsigned long next;
|
|
+
|
|
+ if (pgd_none(*pgd)) {
|
|
+ pgd_entry = __pgd(_KERNPG_TABLE | __pa_nodebug(kasan_zero_p4d));
|
|
+ set_pgd(pgd, pgd_entry);
|
|
+ }
|
|
+
|
|
+ p4d = early_p4d_offset(pgd, addr);
|
|
+ do {
|
|
+ next = p4d_addr_end(addr, end);
|
|
+
|
|
+ if (!p4d_none(*p4d))
|
|
+ continue;
|
|
+
|
|
+ p4d_entry = __p4d(_KERNPG_TABLE | __pa_nodebug(kasan_zero_pud));
|
|
+ set_p4d(p4d, p4d_entry);
|
|
+ } while (p4d++, addr = next, addr != end && p4d_none(*p4d));
|
|
}
|
|
|
|
static void __init kasan_map_early_shadow(pgd_t *pgd)
|
|
{
|
|
- int i;
|
|
- unsigned long start = KASAN_SHADOW_START;
|
|
+ /* See comment in kasan_init() */
|
|
+ unsigned long addr = KASAN_SHADOW_START & PGDIR_MASK;
|
|
unsigned long end = KASAN_SHADOW_END;
|
|
+ unsigned long next;
|
|
|
|
- for (i = pgd_index(start); start < end; i++) {
|
|
- switch (CONFIG_PGTABLE_LEVELS) {
|
|
- case 4:
|
|
- pgd[i] = __pgd(__pa_nodebug(kasan_zero_pud) |
|
|
- _KERNPG_TABLE);
|
|
- break;
|
|
- case 5:
|
|
- pgd[i] = __pgd(__pa_nodebug(kasan_zero_p4d) |
|
|
- _KERNPG_TABLE);
|
|
- break;
|
|
- default:
|
|
- BUILD_BUG();
|
|
- }
|
|
- start += PGDIR_SIZE;
|
|
- }
|
|
+ pgd += pgd_index(addr);
|
|
+ do {
|
|
+ next = pgd_addr_end(addr, end);
|
|
+ kasan_early_p4d_populate(pgd, addr, next);
|
|
+ } while (pgd++, addr = next, addr != end);
|
|
}
|
|
|
|
#ifdef CONFIG_KASAN_INLINE
|
|
@@ -101,7 +137,7 @@ void __init kasan_early_init(void)
|
|
for (i = 0; i < PTRS_PER_PUD; i++)
|
|
kasan_zero_pud[i] = __pud(pud_val);
|
|
|
|
- for (i = 0; CONFIG_PGTABLE_LEVELS >= 5 && i < PTRS_PER_P4D; i++)
|
|
+ for (i = 0; IS_ENABLED(CONFIG_X86_5LEVEL) && i < PTRS_PER_P4D; i++)
|
|
kasan_zero_p4d[i] = __p4d(p4d_val);
|
|
|
|
kasan_map_early_shadow(early_top_pgt);
|
|
@@ -117,12 +153,35 @@ void __init kasan_init(void)
|
|
#endif
|
|
|
|
memcpy(early_top_pgt, init_top_pgt, sizeof(early_top_pgt));
|
|
+
|
|
+ /*
|
|
+ * We use the same shadow offset for 4- and 5-level paging to
|
|
+ * facilitate boot-time switching between paging modes.
|
|
+ * As result in 5-level paging mode KASAN_SHADOW_START and
|
|
+ * KASAN_SHADOW_END are not aligned to PGD boundary.
|
|
+ *
|
|
+ * KASAN_SHADOW_START doesn't share PGD with anything else.
|
|
+ * We claim whole PGD entry to make things easier.
|
|
+ *
|
|
+ * KASAN_SHADOW_END lands in the last PGD entry and it collides with
|
|
+ * bunch of things like kernel code, modules, EFI mapping, etc.
|
|
+ * We need to take extra steps to not overwrite them.
|
|
+ */
|
|
+ if (IS_ENABLED(CONFIG_X86_5LEVEL)) {
|
|
+ void *ptr;
|
|
+
|
|
+ ptr = (void *)pgd_page_vaddr(*pgd_offset_k(KASAN_SHADOW_END));
|
|
+ memcpy(tmp_p4d_table, (void *)ptr, sizeof(tmp_p4d_table));
|
|
+ set_pgd(&early_top_pgt[pgd_index(KASAN_SHADOW_END)],
|
|
+ __pgd(__pa(tmp_p4d_table) | _KERNPG_TABLE));
|
|
+ }
|
|
+
|
|
load_cr3(early_top_pgt);
|
|
__flush_tlb_all();
|
|
|
|
- clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END);
|
|
+ clear_pgds(KASAN_SHADOW_START & PGDIR_MASK, KASAN_SHADOW_END);
|
|
|
|
- kasan_populate_zero_shadow((void *)KASAN_SHADOW_START,
|
|
+ kasan_populate_zero_shadow((void *)(KASAN_SHADOW_START & PGDIR_MASK),
|
|
kasan_mem_to_shadow((void *)PAGE_OFFSET));
|
|
|
|
for (i = 0; i < E820_MAX_ENTRIES; i++) {
|
|
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
|
|
index bf9f03740c30..67d07802ae95 100644
|
|
--- a/arch/x86/Kconfig
|
|
+++ b/arch/x86/Kconfig
|
|
@@ -300,7 +300,6 @@ config ARCH_SUPPORTS_DEBUG_PAGEALLOC
|
|
config KASAN_SHADOW_OFFSET
|
|
hex
|
|
depends on KASAN
|
|
- default 0xdff8000000000000 if X86_5LEVEL
|
|
default 0xdffffc0000000000
|
|
|
|
config HAVE_INTEL_TXT
|
|
--
|
|
2.14.2
|
|
|