]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
x86/alternatives: Initialize temporary mm for patching
authorNadav Amit <namit@vmware.com>
Fri, 26 Apr 2019 23:22:46 +0000 (16:22 -0700)
committerIngo Molnar <mingo@kernel.org>
Tue, 30 Apr 2019 10:37:52 +0000 (12:37 +0200)
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 <luto@kernel.org>
Tested-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Nadav Amit <namit@vmware.com>
Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Rik van Riel <riel@surriel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: akpm@linux-foundation.org
Cc: ard.biesheuvel@linaro.org
Cc: deneen.t.dock@intel.com
Cc: kernel-hardening@lists.openwall.com
Cc: kristen@linux.intel.com
Cc: linux_dti@icloud.com
Cc: will.deacon@arm.com
Link: https://lkml.kernel.org/r/20190426232303.28381-8-nadav.amit@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/text-patching.h
arch/x86/kernel/alternative.c
arch/x86/mm/init.c
init/main.c

index 2779ace16d23f21d5cb7b65faf87f384b3b05268..702db590475365506cd8bdfa1ee57cd315022cba 100644 (file)
@@ -1021,6 +1021,9 @@ static inline void __meminit init_trampoline_default(void)
        /* Default trampoline pgd value */
        trampoline_pgd_entry = init_top_pgt[pgd_index(__PAGE_OFFSET)];
 }
+
+void __init poking_init(void);
+
 # ifdef CONFIG_RANDOMIZE_MEMORY
 void __meminit init_trampoline(void);
 # else
index f8fc8e86cf01b67ddeb4932653079dee8f5439b2..a75eed841eedc1899755580a710b307567a0519b 100644 (file)
@@ -39,5 +39,7 @@ extern void *text_poke_kgdb(void *addr, const void *opcode, size_t len);
 extern int poke_int3_handler(struct pt_regs *regs);
 extern void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler);
 extern int after_bootmem;
+extern __ro_after_init struct mm_struct *poking_mm;
+extern __ro_after_init unsigned long poking_addr;
 
 #endif /* _ASM_X86_TEXT_PATCHING_H */
index 0a814d73547a13c5cc5401174fa8872ea89599f1..11d5c710a94fd321a26682fb21acbf5ba7ad87f8 100644 (file)
@@ -679,6 +679,9 @@ void *__init_or_module text_poke_early(void *addr, const void *opcode,
        return addr;
 }
 
+__ro_after_init struct mm_struct *poking_mm;
+__ro_after_init unsigned long poking_addr;
+
 static void *__text_poke(void *addr, const void *opcode, size_t len)
 {
        unsigned long flags;
index 8dacdb96899ec5a76749751d2675b5b827855141..fd10d91a61152dd18e289f5cf716584a71063100 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/swapfile.h>
 #include <linux/swapops.h>
 #include <linux/kmemleak.h>
+#include <linux/sched/task.h>
 
 #include <asm/set_memory.h>
 #include <asm/e820/api.h>
@@ -23,6 +24,7 @@
 #include <asm/hypervisor.h>
 #include <asm/cpufeature.h>
 #include <asm/pti.h>
+#include <asm/text-patching.h>
 
 /*
  * We need to define the tracepoints somewhere, and tlb.c
@@ -701,6 +703,41 @@ void __init init_mem_mapping(void)
        early_memtest(0, max_pfn_mapped << PAGE_SHIFT);
 }
 
+/*
+ * Initialize an mm_struct to be used during poking and a pointer to be used
+ * during patching.
+ */
+void __init poking_init(void)
+{
+       spinlock_t *ptl;
+       pte_t *ptep;
+
+       poking_mm = copy_init_mm();
+       BUG_ON(!poking_mm);
+
+       /*
+        * Randomize the poking address, but make sure that the following page
+        * will be mapped at the same PMD. We need 2 pages, so find space for 3,
+        * and adjust the address if the PMD ends after the first one.
+        */
+       poking_addr = TASK_UNMAPPED_BASE;
+       if (IS_ENABLED(CONFIG_RANDOMIZE_BASE))
+               poking_addr += (kaslr_get_random_long("Poking") & PAGE_MASK) %
+                       (TASK_SIZE - TASK_UNMAPPED_BASE - 3 * PAGE_SIZE);
+
+       if (((poking_addr + PAGE_SIZE) & ~PMD_MASK) == 0)
+               poking_addr += PAGE_SIZE;
+
+       /*
+        * We need to trigger the allocation of the page-tables that will be
+        * needed for poking now. Later, poking may be performed in an atomic
+        * section, which might cause allocation to fail.
+        */
+       ptep = get_locked_pte(poking_mm, poking_addr, &ptl);
+       BUG_ON(!ptep);
+       pte_unmap_unlock(ptep, ptl);
+}
+
 /*
  * devmem_is_allowed() checks to see if /dev/mem access to a certain address
  * is valid. The argument is a physical page number.
index 7d4025d665eb95ee439ddb4e5e564aff8fa09c24..95dd9406ee31ed386d5a1be83bc2309566831452 100644 (file)
@@ -504,6 +504,8 @@ void __init __weak thread_stack_cache_init(void)
 
 void __init __weak mem_encrypt_init(void) { }
 
+void __init __weak poking_init(void) { }
+
 bool initcall_debug;
 core_param(initcall_debug, initcall_debug, bool, 0644);
 
@@ -737,6 +739,7 @@ asmlinkage __visible void __init start_kernel(void)
        taskstats_init_early();
        delayacct_init();
 
+       poking_init();
        check_bugs();
 
        acpi_subsystem_init();