This patch series:
- fixes kernel halt caused by incorrect physical addresses
in KASan shadow region page tables in case of non-zero phys_base;
- consolidates early KASan initialization.
Changes from v2:
- move KASan shadow region page tables to BSS;
- use __PAGE_KERNEL flags for describing kasan_zero_page in kasan_zero_pte.
Changes from v3:
- improve commit message.
Changes from v4:
- add Andrey's patch which removes faulty clear_page(init_level4_pgt);
- call kasan_map_early_shadow() for early_level4_pgt and init_level4_pgt
in kasan_early_init().
Alexander Popov (1):
x86_64: fix KASan shadow region page tables
Andrey Ryabinin (1):
x86_64: remove not needed clear_page for init_level4_page
arch/x86/include/asm/kasan.h | 8 ++------
arch/x86/kernel/head64.c | 12 ++++++------
arch/x86/kernel/head_64.S | 29 -----------------------------
arch/x86/mm/kasan_init_64.c | 36 ++++++++++++++++++++++++++++++++++--
4 files changed, 42 insertions(+), 43 deletions(-)
--
1.9.1
From: Andrey Ryabinin <[email protected]>
Commit 8170e6bed465 ("x86, 64bit: Use a #PF handler to materialize
early mappings on demand") introduced clear_page(init_level4_pgt);
call in x86_64_start_kernel(). However, this clear_page is useless
because init_level4_page already filled with zeroes in head_64.S
Commit message in 8170e6bed465 says that this clear_page() was
dropped in v7, but it accidentally reappeared in later versions
of that patchset.
Signed-off-by: Andrey Ryabinin <[email protected]>
---
arch/x86/kernel/head64.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 5a46681..6a6eefd 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -177,7 +177,6 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
*/
load_ucode_bsp();
- clear_page(init_level4_pgt);
/* set init_level4_pgt kernel high mapping*/
init_level4_pgt[511] = early_level4_pgt[511];
--
1.9.1
Physical addresses in KASan shadow region page tables need fixup similarly
to the other page tables. Current code doesn't do it which causes
kernel halt if phys_base is not zero.
So let's initialize KASan shadow region page tables in kasan_early_init()
using __pa_nodebug() which considers phys_base.
Signed-off-by: Alexander Popov <[email protected]>
---
arch/x86/include/asm/kasan.h | 8 ++------
arch/x86/kernel/head64.c | 11 ++++++-----
arch/x86/kernel/head_64.S | 29 -----------------------------
arch/x86/mm/kasan_init_64.c | 36 ++++++++++++++++++++++++++++++++++--
4 files changed, 42 insertions(+), 42 deletions(-)
diff --git a/arch/x86/include/asm/kasan.h b/arch/x86/include/asm/kasan.h
index 8b22422..74a2a8d 100644
--- a/arch/x86/include/asm/kasan.h
+++ b/arch/x86/include/asm/kasan.h
@@ -14,15 +14,11 @@
#ifndef __ASSEMBLY__
-extern pte_t kasan_zero_pte[];
-extern pte_t kasan_zero_pmd[];
-extern pte_t kasan_zero_pud[];
-
#ifdef CONFIG_KASAN
-void __init kasan_map_early_shadow(pgd_t *pgd);
+void __init kasan_early_init(void);
void __init kasan_init(void);
#else
-static inline void kasan_map_early_shadow(pgd_t *pgd) { }
+static inline void kasan_early_init(void) { }
static inline void kasan_init(void) { }
#endif
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 6a6eefd..74da193 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -161,11 +161,14 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
/* Kill off the identity-map trampoline */
reset_early_page_tables();
- kasan_map_early_shadow(early_level4_pgt);
-
- /* clear bss before set_intr_gate with early_idt_handler */
+ /*
+ * Clear bss before kasan_early_init and set_intr_gate
+ * with early_idt_handler
+ */
clear_bss();
+ kasan_early_init();
+
for (i = 0; i < NUM_EXCEPTION_VECTORS; i++)
set_intr_gate(i, early_idt_handler_array[i]);
load_idt((const struct desc_ptr *)&idt_descr);
@@ -180,8 +183,6 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
/* set init_level4_pgt kernel high mapping*/
init_level4_pgt[511] = early_level4_pgt[511];
- kasan_map_early_shadow(init_level4_pgt);
-
x86_64_start_reservations(real_mode_data);
}
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index df7e780..7e5da2c 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -516,38 +516,9 @@ ENTRY(phys_base)
/* This must match the first entry in level2_kernel_pgt */
.quad 0x0000000000000000
-#ifdef CONFIG_KASAN
-#define FILL(VAL, COUNT) \
- .rept (COUNT) ; \
- .quad (VAL) ; \
- .endr
-
-NEXT_PAGE(kasan_zero_pte)
- FILL(kasan_zero_page - __START_KERNEL_map + _KERNPG_TABLE, 512)
-NEXT_PAGE(kasan_zero_pmd)
- FILL(kasan_zero_pte - __START_KERNEL_map + _KERNPG_TABLE, 512)
-NEXT_PAGE(kasan_zero_pud)
- FILL(kasan_zero_pmd - __START_KERNEL_map + _KERNPG_TABLE, 512)
-
-#undef FILL
-#endif
-
-
#include "../../x86/xen/xen-head.S"
__PAGE_ALIGNED_BSS
NEXT_PAGE(empty_zero_page)
.skip PAGE_SIZE
-#ifdef CONFIG_KASAN
-/*
- * This page used as early shadow. We don't use empty_zero_page
- * at early stages, stack instrumentation could write some garbage
- * to this page.
- * Latter we reuse it as zero shadow for large ranges of memory
- * that allowed to access, but not instrumented by kasan
- * (vmalloc/vmemmap ...).
- */
-NEXT_PAGE(kasan_zero_page)
- .skip PAGE_SIZE
-#endif
diff --git a/arch/x86/mm/kasan_init_64.c b/arch/x86/mm/kasan_init_64.c
index 4860906..0e4a05f 100644
--- a/arch/x86/mm/kasan_init_64.c
+++ b/arch/x86/mm/kasan_init_64.c
@@ -11,7 +11,19 @@
extern pgd_t early_level4_pgt[PTRS_PER_PGD];
extern struct range pfn_mapped[E820_X_MAX];
-extern unsigned char kasan_zero_page[PAGE_SIZE];
+static pud_t kasan_zero_pud[PTRS_PER_PUD] __page_aligned_bss;
+static pmd_t kasan_zero_pmd[PTRS_PER_PMD] __page_aligned_bss;
+static pte_t kasan_zero_pte[PTRS_PER_PTE] __page_aligned_bss;
+
+/*
+ * This page used as early shadow. We don't use empty_zero_page
+ * at early stages, stack instrumentation could write some garbage
+ * to this page.
+ * Latter we reuse it as zero shadow for large ranges of memory
+ * that allowed to access, but not instrumented by kasan
+ * (vmalloc/vmemmap ...).
+ */
+static unsigned char kasan_zero_page[PAGE_SIZE] __page_aligned_bss;
static int __init map_range(struct range *range)
{
@@ -36,7 +48,7 @@ static void __init clear_pgds(unsigned long start,
pgd_clear(pgd_offset_k(start));
}
-void __init kasan_map_early_shadow(pgd_t *pgd)
+static void __init kasan_map_early_shadow(pgd_t *pgd)
{
int i;
unsigned long start = KASAN_SHADOW_START;
@@ -166,6 +178,26 @@ static struct notifier_block kasan_die_notifier = {
};
#endif
+void __init kasan_early_init(void)
+{
+ int i;
+ pteval_t pte_val = __pa_nodebug(kasan_zero_page) | __PAGE_KERNEL;
+ pmdval_t pmd_val = __pa_nodebug(kasan_zero_pte) | _KERNPG_TABLE;
+ pudval_t pud_val = __pa_nodebug(kasan_zero_pmd) | _KERNPG_TABLE;
+
+ for (i = 0; i < PTRS_PER_PTE; i++)
+ kasan_zero_pte[i] = __pte(pte_val);
+
+ for (i = 0; i < PTRS_PER_PMD; i++)
+ kasan_zero_pmd[i] = __pmd(pmd_val);
+
+ for (i = 0; i < PTRS_PER_PUD; i++)
+ kasan_zero_pud[i] = __pud(pud_val);
+
+ kasan_map_early_shadow(early_level4_pgt);
+ kasan_map_early_shadow(init_level4_pgt);
+}
+
void __init kasan_init(void)
{
int i;
--
1.9.1
2015-06-09 12:42 GMT+03:00 Alexander Popov <[email protected]>:
> Physical addresses in KASan shadow region page tables need fixup similarly
> to the other page tables. Current code doesn't do it which causes
> kernel halt if phys_base is not zero.
> So let's initialize KASan shadow region page tables in kasan_early_init()
> using __pa_nodebug() which considers phys_base.
>
> Signed-off-by: Alexander Popov <[email protected]>
Acked-by: Andrey Ryabinin <[email protected]>
On Tue, Jun 09, 2015 at 12:42:00PM +0300, Alexander Popov wrote:
> From: Andrey Ryabinin <[email protected]>
>
> Commit 8170e6bed465 ("x86, 64bit: Use a #PF handler to materialize
> early mappings on demand") introduced clear_page(init_level4_pgt);
> call in x86_64_start_kernel(). However, this clear_page is useless
> because init_level4_page already filled with zeroes in head_64.S
I really doubt that, see below:
> Commit message in 8170e6bed465 says that this clear_page() was
> dropped in v7, but it accidentally reappeared in later versions
> of that patchset.
>
> Signed-off-by: Andrey Ryabinin <[email protected]>
> ---
> arch/x86/kernel/head64.c | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
> index 5a46681..6a6eefd 100644
> --- a/arch/x86/kernel/head64.c
> +++ b/arch/x86/kernel/head64.c
> @@ -177,7 +177,6 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
> */
> load_ucode_bsp();
>
> - clear_page(init_level4_pgt);
> /* set init_level4_pgt kernel high mapping*/
> init_level4_pgt[511] = early_level4_pgt[511];
vmlinux has:
ffffffff81a00000 <init_level4_pgt>:
ffffffff81a00000: 63 10 movslq (%rax),%edx
ffffffff81a00002: a0 01 00 00 00 00 00 movabs 0x1,%al
ffffffff81a00009: 00 00
...
ffffffff81a0087f: 00 63 10 add %ah,0x10(%rbx)
ffffffff81a00882: a0 01 00 00 00 00 00 movabs 0x1,%al
ffffffff81a00889: 00 00
...
ffffffff81a00ff7: 00 67 30 add %ah,0x30(%rdi)
ffffffff81a00ffa: a0 01 00 00 00 00 63 movabs 0xa020630000000001,%al
ffffffff81a01001: 20 a0
ffffffff81a01000 <level3_ident_pgt>:
ffffffff81a01000: 63 20 movslq (%rax),%esp
ffffffff81a01002: a0 01 00 00 00 00 00 movabs 0x1,%al
ffffffff81a01009: 00 00
...
Booting a kvm quest and halting it before the clear_page:
---
/*
* Load microcode early on BSP.
*/
load_ucode_bsp();
// clear_page(init_level4_pgt);
while(1)
cpu_relax();
/* set init_level4_pgt kernel high mapping*/
init_level4_pgt[511] = early_level4_pgt[511];
---
and dumping the memory at ffffffff81a00000 gives:
---
00000000 63 10 a0 01 00 00 00 00 00 00 00 00 00 00 00 00 |c...............|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000880 63 10 a0 01 00 00 00 00 00 00 00 00 00 00 00 00 |c...............|
00000890 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000ff0 00 00 00 00 00 00 00 00 67 30 a0 01 00 00 00 00 |........g0......|
00001000
---
These are basically the PTE entries it gets for the CONFIG_XEN case
which we clear because we're on baremetal.
Now my hunch is that those entries get overwritten later but I wouldn't
want to debug any strange bugs from leftovers in init_level4_pgt so
having the clear_page() is actually a good thing.
--
Regards/Gruss,
Boris.
ECO tip #101: Trim your mails when you reply.
--
On Tue, Jun 16, 2015 at 01:16:32PM +0200, Borislav Petkov wrote:
> Now my hunch is that those entries get overwritten later but I wouldn't
> want to debug any strange bugs from leftovers in init_level4_pgt so
> having the clear_page() is actually a good thing.
So I guess we can do that:
#ifndef CONFIG_KASAN
clear_page(init_level4_pgt);
#endif
Hmm...
--
Regards/Gruss,
Boris.
ECO tip #101: Trim your mails when you reply.
--
On 06/16/2015 02:34 PM, Borislav Petkov wrote:
> On Tue, Jun 16, 2015 at 01:16:32PM +0200, Borislav Petkov wrote:
>> Now my hunch is that those entries get overwritten later but I wouldn't
>> want to debug any strange bugs from leftovers in init_level4_pgt so
>> having the clear_page() is actually a good thing.
>
> So I guess we can do that:
>
> #ifndef CONFIG_KASAN
> clear_page(init_level4_pgt);
> #endif
>
Ugh..
Can't we just move clear_page(init_level4_pgt) higher? Before or right after clear_bss() (iow before kasan_early_init()).
On Tue, Jun 16, 2015 at 02:45:06PM +0300, Andrey Ryabinin wrote:
> Can't we just move clear_page(init_level4_pgt) higher? Before or right
> after clear_bss() (iow before kasan_early_init()).
That sounds much better. And I don't see anything depending on
init_level4_pgt before we clear it. And it boots here if I move it
before
kasan_map_early_shadow(early_level4_pgt);
--
Regards/Gruss,
Boris.
ECO tip #101: Trim your mails when you reply.
--
On 16.06.2015 18:46, Borislav Petkov wrote:
> On Tue, Jun 16, 2015 at 02:45:06PM +0300, Andrey Ryabinin wrote:
>> Can't we just move clear_page(init_level4_pgt) higher? Before or right
>> after clear_bss() (iow before kasan_early_init()).
>
> That sounds much better. And I don't see anything depending on
> init_level4_pgt before we clear it. And it boots here if I move it
> before
>
> kasan_map_early_shadow(early_level4_pgt);
Thanks, Borislav and Andrey.
I'll return with version 6.
Best regards,
Alexander