efi: arm64: Wire up BTI annotation in memory attributes table
authorArd Biesheuvel <ardb@kernel.org>
Wed, 1 Feb 2023 08:50:07 +0000 (09:50 +0100)
committerArd Biesheuvel <ardb@kernel.org>
Thu, 9 Feb 2023 16:39:16 +0000 (17:39 +0100)
UEFI v2.10 extends the EFI memory attributes table with a flag that
indicates whether or not all RuntimeServicesCode regions were
constructed with BTI landing pads, permitting the OS to map these
regions with BTI restrictions enabled.

So let's take this into account on arm64.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Will Deacon <will@kernel.org>
arch/arm64/kernel/efi.c
arch/arm64/kernel/traps.c

index 78ffd5aaddcbbaeed3db47fe4366a85c345357c1..db9007cae93d6593777cb321ac7afbfe44c1eeb7 100644 (file)
@@ -96,15 +96,24 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
        return 0;
 }
 
+struct set_perm_data {
+       const efi_memory_desc_t *md;
+       bool                    has_bti;
+};
+
 static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data)
 {
-       efi_memory_desc_t *md = data;
+       struct set_perm_data *spd = data;
+       const efi_memory_desc_t *md = spd->md;
        pte_t pte = READ_ONCE(*ptep);
 
        if (md->attribute & EFI_MEMORY_RO)
                pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
        if (md->attribute & EFI_MEMORY_XP)
                pte = set_pte_bit(pte, __pgprot(PTE_PXN));
+       else if (IS_ENABLED(CONFIG_ARM64_BTI_KERNEL) &&
+                system_supports_bti() && spd->has_bti)
+               pte = set_pte_bit(pte, __pgprot(PTE_GP));
        set_pte(ptep, pte);
        return 0;
 }
@@ -113,6 +122,8 @@ int __init efi_set_mapping_permissions(struct mm_struct *mm,
                                       efi_memory_desc_t *md,
                                       bool has_bti)
 {
+       struct set_perm_data data = { md, has_bti };
+
        BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
               md->type != EFI_RUNTIME_SERVICES_DATA);
 
@@ -128,7 +139,7 @@ int __init efi_set_mapping_permissions(struct mm_struct *mm,
         */
        return apply_to_page_range(mm, md->virt_addr,
                                   md->num_pages << EFI_PAGE_SHIFT,
-                                  set_permissions, md);
+                                  set_permissions, &data);
 }
 
 /*
index 4c0caa589e12de2a7ee0569d8f8e948ea1825174..1f366b94ea8e233ac87a1654312d6c6bc928fbbb 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/kexec.h>
 #include <linux/delay.h>
+#include <linux/efi.h>
 #include <linux/init.h>
 #include <linux/sched/signal.h>
 #include <linux/sched/debug.h>
@@ -33,6 +34,7 @@
 #include <asm/cpufeature.h>
 #include <asm/daifflags.h>
 #include <asm/debug-monitors.h>
+#include <asm/efi.h>
 #include <asm/esr.h>
 #include <asm/exception.h>
 #include <asm/extable.h>
@@ -492,6 +494,10 @@ void do_el0_bti(struct pt_regs *regs)
 
 void do_el1_bti(struct pt_regs *regs, unsigned long esr)
 {
+       if (efi_runtime_fixup_exception(regs, "BTI violation")) {
+               regs->pstate &= ~PSR_BTYPE_MASK;
+               return;
+       }
        die("Oops - BTI", regs, esr);
 }