Skip to content

Commit b64dfcd

Browse files
committed
x86/mm: Prevent early boot triple-faults with instrumentation
Commit in Fixes added a global TLB flush on the early boot path, after the kernel switches off of the trampoline page table. Compiler profiling options enabled with GCOV_PROFILE add additional measurement code on clang which needs to be initialized prior to use. The global flush in x86_64_start_kernel() happens before those initializations can happen, leading to accessing invalid memory. GCOV_PROFILE builds with gcc are still ok so this is clang-specific. The second issue this fixes is with KASAN: for a similar reason, kasan_early_init() needs to have happened before KASAN-instrumented functions are called. Therefore, reorder the flush to happen after the KASAN early init and prevent the compilers from adding profiling instrumentation to native_write_cr4(). Fixes: f154f29 ("x86/mm/64: Flush global TLB on boot and AP bringup") Reported-by: "J. Bruce Fields" <[email protected]> Reported-by: kernel test robot <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Tested-by: Carel Si <[email protected]> Tested-by: "J. Bruce Fields" <[email protected]> Link: https://lore.kernel.org/r/20211209144141.GC25654@xsang-OptiPlex-9020
1 parent 35fa745 commit b64dfcd

File tree

2 files changed

+15
-3
lines changed

2 files changed

+15
-3
lines changed

arch/x86/kernel/cpu/common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ void native_write_cr0(unsigned long val)
384384
}
385385
EXPORT_SYMBOL(native_write_cr0);
386386

387-
void native_write_cr4(unsigned long val)
387+
void __no_profile native_write_cr4(unsigned long val)
388388
{
389389
unsigned long bits_changed = 0;
390390

arch/x86/kernel/head64.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -483,10 +483,12 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
483483
/* Kill off the identity-map trampoline */
484484
reset_early_page_tables();
485485

486-
__native_tlb_flush_global(native_read_cr4());
487-
488486
clear_bss();
489487

488+
/*
489+
* This needs to happen *before* kasan_early_init() because latter maps stuff
490+
* into that page.
491+
*/
490492
clear_page(init_top_pgt);
491493

492494
/*
@@ -498,6 +500,16 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
498500

499501
kasan_early_init();
500502

503+
/*
504+
* Flush global TLB entries which could be left over from the trampoline page
505+
* table.
506+
*
507+
* This needs to happen *after* kasan_early_init() as KASAN-enabled .configs
508+
* instrument native_write_cr4() so KASAN must be initialized for that
509+
* instrumentation to work.
510+
*/
511+
__native_tlb_flush_global(this_cpu_read(cpu_tlbstate.cr4));
512+
501513
idt_setup_early_handler();
502514

503515
copy_bootdata(__va(real_mode_data));

0 commit comments

Comments
 (0)