Skip to content

Commit 4fc1970

Browse files
anadavIngo Molnar
authored andcommitted
x86/alternatives: Initialize temporary mm for patching
To prevent improper use of the PTEs that are used for text patching, the next patches will use a temporary mm struct. Initailize it by copying the init mm. The address that will be used for patching is taken from the lower area that is usually used for the task memory. Doing so prevents the need to frequently synchronize the temporary-mm (e.g., when BPF programs are installed), since different PGDs are used for the task memory. Finally, randomize the address of the PTEs to harden against exploits that use these PTEs. Suggested-by: Andy Lutomirski <[email protected]> Tested-by: Masami Hiramatsu <[email protected]> Signed-off-by: Nadav Amit <[email protected]> Signed-off-by: Rick Edgecombe <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Masami Hiramatsu <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Dave Hansen <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Kees Cook <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Rik van Riel <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 13585fa commit 4fc1970

File tree

5 files changed

+48
-0
lines changed

5 files changed

+48
-0
lines changed

arch/x86/include/asm/pgtable.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,9 @@ static inline void __meminit init_trampoline_default(void)
10211021
/* Default trampoline pgd value */
10221022
trampoline_pgd_entry = init_top_pgt[pgd_index(__PAGE_OFFSET)];
10231023
}
1024+
1025+
void __init poking_init(void);
1026+
10241027
# ifdef CONFIG_RANDOMIZE_MEMORY
10251028
void __meminit init_trampoline(void);
10261029
# else

arch/x86/include/asm/text-patching.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,7 @@ extern void *text_poke_kgdb(void *addr, const void *opcode, size_t len);
3939
extern int poke_int3_handler(struct pt_regs *regs);
4040
extern void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler);
4141
extern int after_bootmem;
42+
extern __ro_after_init struct mm_struct *poking_mm;
43+
extern __ro_after_init unsigned long poking_addr;
4244

4345
#endif /* _ASM_X86_TEXT_PATCHING_H */

arch/x86/kernel/alternative.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,9 @@ void *__init_or_module text_poke_early(void *addr, const void *opcode,
679679
return addr;
680680
}
681681

682+
__ro_after_init struct mm_struct *poking_mm;
683+
__ro_after_init unsigned long poking_addr;
684+
682685
static void *__text_poke(void *addr, const void *opcode, size_t len)
683686
{
684687
unsigned long flags;

arch/x86/mm/init.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <linux/swapfile.h>
77
#include <linux/swapops.h>
88
#include <linux/kmemleak.h>
9+
#include <linux/sched/task.h>
910

1011
#include <asm/set_memory.h>
1112
#include <asm/e820/api.h>
@@ -23,6 +24,7 @@
2324
#include <asm/hypervisor.h>
2425
#include <asm/cpufeature.h>
2526
#include <asm/pti.h>
27+
#include <asm/text-patching.h>
2628

2729
/*
2830
* We need to define the tracepoints somewhere, and tlb.c
@@ -701,6 +703,41 @@ void __init init_mem_mapping(void)
701703
early_memtest(0, max_pfn_mapped << PAGE_SHIFT);
702704
}
703705

706+
/*
707+
* Initialize an mm_struct to be used during poking and a pointer to be used
708+
* during patching.
709+
*/
710+
void __init poking_init(void)
711+
{
712+
spinlock_t *ptl;
713+
pte_t *ptep;
714+
715+
poking_mm = copy_init_mm();
716+
BUG_ON(!poking_mm);
717+
718+
/*
719+
* Randomize the poking address, but make sure that the following page
720+
* will be mapped at the same PMD. We need 2 pages, so find space for 3,
721+
* and adjust the address if the PMD ends after the first one.
722+
*/
723+
poking_addr = TASK_UNMAPPED_BASE;
724+
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE))
725+
poking_addr += (kaslr_get_random_long("Poking") & PAGE_MASK) %
726+
(TASK_SIZE - TASK_UNMAPPED_BASE - 3 * PAGE_SIZE);
727+
728+
if (((poking_addr + PAGE_SIZE) & ~PMD_MASK) == 0)
729+
poking_addr += PAGE_SIZE;
730+
731+
/*
732+
* We need to trigger the allocation of the page-tables that will be
733+
* needed for poking now. Later, poking may be performed in an atomic
734+
* section, which might cause allocation to fail.
735+
*/
736+
ptep = get_locked_pte(poking_mm, poking_addr, &ptl);
737+
BUG_ON(!ptep);
738+
pte_unmap_unlock(ptep, ptl);
739+
}
740+
704741
/*
705742
* devmem_is_allowed() checks to see if /dev/mem access to a certain address
706743
* is valid. The argument is a physical page number.

init/main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,8 @@ void __init __weak thread_stack_cache_init(void)
504504

505505
void __init __weak mem_encrypt_init(void) { }
506506

507+
void __init __weak poking_init(void) { }
508+
507509
bool initcall_debug;
508510
core_param(initcall_debug, initcall_debug, bool, 0644);
509511

@@ -737,6 +739,7 @@ asmlinkage __visible void __init start_kernel(void)
737739
taskstats_init_early();
738740
delayacct_init();
739741

742+
poking_init();
740743
check_bugs();
741744

742745
acpi_subsystem_init();

0 commit comments

Comments
 (0)