arm64: mm: Map entry trampoline into trampoline and kernel page tables
authorWill Deacon <will.deacon@arm.com>
Tue, 3 Apr 2018 11:09:05 +0000 (12:09 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 8 Apr 2018 10:12:52 +0000 (12:12 +0200)
commit 51a0048beb44 upstream.

The exception entry trampoline needs to be mapped at the same virtual
address in both the trampoline page table (which maps nothing else)
and also the kernel page table, so that we can swizzle TTBR1_EL1 on
exceptions from and return to EL0.

This patch maps the trampoline at a fixed virtual address in the fixmap
area of the kernel virtual address space, which allows the kernel proper
to be randomized with respect to the trampoline when KASLR is enabled.

Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Laura Abbott <labbott@redhat.com>
Tested-by: Shanker Donthineni <shankerd@codeaurora.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Alex Shi <alex.shi@linaro.org>
Signed-off-by: Mark Rutland <mark.rutland@arm.com> [v4.9 backport]
Tested-by: Will Deacon <will.deacon@arm.com>
Tested-by: Greg Hackmann <ghackmann@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/arm64/include/asm/fixmap.h
arch/arm64/include/asm/pgtable.h
arch/arm64/kernel/asm-offsets.c
arch/arm64/mm/mmu.c

index caf86be815ba2cfa26d6cbcab8ee1cd7f6bdf158..7b1d88c18143ddea7075e7c3bac43328640330a8 100644 (file)
@@ -51,6 +51,11 @@ enum fixed_addresses {
 
        FIX_EARLYCON_MEM_BASE,
        FIX_TEXT_POKE0,
+
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+       FIX_ENTRY_TRAMP_TEXT,
+#define TRAMP_VALIAS           (__fix_to_virt(FIX_ENTRY_TRAMP_TEXT))
+#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
        __end_of_permanent_fixed_addresses,
 
        /*
index 7acd3c5c7643cd02f8916bd838bc06247da966c5..3a30a3994e4a259b93f2ccf3c5c33e63d435f8e2 100644 (file)
@@ -692,6 +692,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
+extern pgd_t tramp_pg_dir[PTRS_PER_PGD];
 
 /*
  * Encode and decode a swap entry:
index c58ddf8c40622b9fc16a3e57ab4ace0ea49b89d6..5f4bf3c6f016bc199c2b18b13885c7113cf04bce 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/kvm_host.h>
 #include <linux/suspend.h>
 #include <asm/cpufeature.h>
+#include <asm/fixmap.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
 #include <asm/smp_plat.h>
@@ -144,11 +145,14 @@ int main(void)
   DEFINE(ARM_SMCCC_RES_X2_OFFS,                offsetof(struct arm_smccc_res, a2));
   DEFINE(ARM_SMCCC_QUIRK_ID_OFFS,      offsetof(struct arm_smccc_quirk, id));
   DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS,   offsetof(struct arm_smccc_quirk, state));
-
   BLANK();
   DEFINE(HIBERN_PBE_ORIG,      offsetof(struct pbe, orig_address));
   DEFINE(HIBERN_PBE_ADDR,      offsetof(struct pbe, address));
   DEFINE(HIBERN_PBE_NEXT,      offsetof(struct pbe, next));
   DEFINE(ARM64_FTR_SYSVAL,     offsetof(struct arm64_ftr_reg, sys_val));
+  BLANK();
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+  DEFINE(TRAMP_VALIAS,         TRAMP_VALIAS);
+#endif
   return 0;
 }
index 638f7f2bd79cde2129497581365d7fdfba6e1ed8..3a57fec16b32521aec7df5761ef3e509e65d910f 100644 (file)
@@ -419,6 +419,29 @@ static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end,
        vm_area_add_early(vma);
 }
 
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+static int __init map_entry_trampoline(void)
+{
+       extern char __entry_tramp_text_start[];
+
+       pgprot_t prot = rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
+       phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start);
+
+       /* The trampoline is always mapped and can therefore be global */
+       pgprot_val(prot) &= ~PTE_NG;
+
+       /* Map only the text into the trampoline page table */
+       memset(tramp_pg_dir, 0, PGD_SIZE);
+       __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, PAGE_SIZE,
+                            prot, pgd_pgtable_alloc, 0);
+
+       /* ...as well as the kernel page table */
+       __set_fixmap(FIX_ENTRY_TRAMP_TEXT, pa_start, prot);
+       return 0;
+}
+core_initcall(map_entry_trampoline);
+#endif
+
 /*
  * Create fine-grained mappings for the kernel.
  */