2015-06-02 12:57:16

by Alexander Popov

[permalink] [raw]
Subject: [PATCH v4 1/1] x86_64: fix KASan shadow region page tables

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


2015-06-03 07:44:54

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH v4 1/1] x86_64: fix KASan shadow region page tables


* 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

2015-06-03 08:36:54

by Alexander Popov

[permalink] [raw]
Subject: Re: [PATCH v4 1/1] x86_64: fix KASan shadow region page tables

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

2015-06-03 08:45:00

by Andrey Ryabinin

[permalink] [raw]
Subject: Re: [PATCH v4 1/1] x86_64: fix KASan shadow region page tables

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];

2015-06-03 14:09:37

by Alexander Popov

[permalink] [raw]
Subject: Re: [PATCH v4 1/1] x86_64: fix KASan shadow region page tables

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

2015-06-03 16:34:07

by Andrey Ryabinin

[permalink] [raw]
Subject: Re: [PATCH v4 1/1] x86_64: fix KASan shadow region page tables

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.