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 in early_idt_handler 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]>
---
Notes:
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.
arch/x86/include/asm/kasan.h | 6 ++----
arch/x86/kernel/head64.c | 10 +++++++---
arch/x86/kernel/head_64.S | 29 -----------------------------
arch/x86/mm/kasan_init_64.c | 31 ++++++++++++++++++++++++++++++-
4 files changed, 39 insertions(+), 37 deletions(-)
diff --git a/arch/x86/include/asm/kasan.h b/arch/x86/include/asm/kasan.h
index 8b22422..d505f76 100644
--- a/arch/x86/include/asm/kasan.h
+++ b/arch/x86/include/asm/kasan.h
@@ -14,15 +14,13 @@
#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 2b55ee6..e9a84a1 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -161,11 +161,15 @@ 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();
+ kasan_map_early_shadow(early_level4_pgt);
+
for (i = 0; i < NUM_EXCEPTION_VECTORS; i++)
set_intr_gate(i, early_idt_handlers[i]);
load_idt((const struct desc_ptr *)&idt_descr);
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index ae6588b..b5c80c8 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -514,38 +514,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..9968732 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)
{
@@ -166,6 +178,23 @@ 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);
+}
+
void __init kasan_init(void)
{
int i;
--
1.9.1
* Alexander Popov <[email protected]> wrote:
> #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 2b55ee6..e9a84a1 100644
> --- a/arch/x86/kernel/head64.c
> +++ b/arch/x86/kernel/head64.c
> @@ -161,11 +161,15 @@ 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();
> + kasan_map_early_shadow(early_level4_pgt);
So why isn't kasan_map_early_shadow() called in kasan_early_init()?
High level x86 init code should not be polluted with too many low level details.
Thanks,
Ingo
On 03.06.2015 10:44, Ingo Molnar wrote:
>
> * Alexander Popov <[email protected]> wrote:
>> + kasan_early_init();
>> + kasan_map_early_shadow(early_level4_pgt);
>
> So why isn't kasan_map_early_shadow() called in kasan_early_init()?
>
> High level x86 init code should not be polluted with too many low level details.
Hello, Ingo.
kasan_map_early_shadow() is called twice in x86_64_start_kernel():
once for early_level4_pgt and then later for init_level4_pgt.
I've decided to introduce separate kasan_early_init() to avoid big changes
which can bring consequences that I don't understand.
Best regards,
Alexander
On 06/03/2015 10:44 AM, Ingo Molnar wrote:
>
> * Alexander Popov <[email protected]> wrote:
>
>> #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 2b55ee6..e9a84a1 100644
>> --- a/arch/x86/kernel/head64.c
>> +++ b/arch/x86/kernel/head64.c
>> @@ -161,11 +161,15 @@ 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();
>> + kasan_map_early_shadow(early_level4_pgt);
>
> So why isn't kasan_map_early_shadow() called in kasan_early_init()?
>
> High level x86 init code should not be polluted with too many low level details.
>
Agreed. Eventually, with the patch bellow, we could get rid of the second
kasan_map_early_shadow(init_level4_pgt) call in x86_64_start_kernel().
Make it static, and call it from kasan_early_init() only.
------------------------------------------------------
From: Andrey Ryabinin <[email protected]>
Subject: [PATCH] x86_64: remove not needed clear_page for init_level4_page
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];
On 03.06.2015 11:44, Andrey Ryabinin wrote:
> On 06/03/2015 10:44 AM, Ingo Molnar wrote:
>>
>> * Alexander Popov <[email protected]> wrote:
>>
>>> #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 2b55ee6..e9a84a1 100644
>>> --- a/arch/x86/kernel/head64.c
>>> +++ b/arch/x86/kernel/head64.c
>>> @@ -161,11 +161,15 @@ 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();
>>> + kasan_map_early_shadow(early_level4_pgt);
>>
>> So why isn't kasan_map_early_shadow() called in kasan_early_init()?
>>
>> High level x86 init code should not be polluted with too many low level details.
>>
>
> Agreed. Eventually, with the patch bellow, we could get rid of the second
> kasan_map_early_shadow(init_level4_pgt) call in x86_64_start_kernel().
> Make it static, and call it from kasan_early_init() only.
>
> ------------------------------------------------------
> From: Andrey Ryabinin <[email protected]>
> Subject: [PATCH] x86_64: remove not needed clear_page for init_level4_page
>
> 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];
>
Hello Ingo and Andrey.
Should I make a "patch series" containing Andrey's patch and the 5'th version
of my patch or just include changes from Andrey's patch into mine?
Best regards,
Alexander
On 06/03/2015 05:10 PM, Alexander Popov wrote:
>
> Hello Ingo and Andrey.
>
> Should I make a "patch series" containing Andrey's patch and the 5'th version
> of my patch or just include changes from Andrey's patch into mine?
>
These patches contain logically separate changes, so please don't fold them into one.