efi: Discover BTI support in runtime services regions
authorArd Biesheuvel <ardb@kernel.org>
Wed, 1 Feb 2023 08:48:12 +0000 (09:48 +0100)
committerArd Biesheuvel <ardb@kernel.org>
Sat, 4 Feb 2023 08:19:02 +0000 (09:19 +0100)
Add the generic plumbing to detect whether or not the runtime code
regions were constructed with BTI/IBT landing pads by the firmware,
permitting the OS to enable enforcement when mapping these regions into
the OS's address space.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
arch/arm/include/asm/efi.h
arch/arm/kernel/efi.c
arch/arm64/include/asm/efi.h
arch/arm64/kernel/efi.c
arch/riscv/include/asm/efi.h
arch/riscv/kernel/efi.c
arch/x86/platform/efi/efi_64.c
drivers/firmware/efi/memattr.c
include/linux/efi.h

index b95241b1ca656f3c9152825cdb5549742753494c..78282ced50387dd31f9c366d5b7423ebc1f4f92f 100644 (file)
@@ -20,7 +20,7 @@ void efi_init(void);
 void arm_efi_init(void);
 
 int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
-int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
+int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md, bool);
 
 #define arch_efi_call_virt_setup()     efi_virtmap_load()
 #define arch_efi_call_virt_teardown()  efi_virtmap_unload()
index 882104f43b3b09281e406d2ed8d7244726b32980..e2b9d2618c6727c64b0f1b0ed8788a36ce1049ff 100644 (file)
@@ -23,7 +23,8 @@ static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data)
 }
 
 int __init efi_set_mapping_permissions(struct mm_struct *mm,
-                                      efi_memory_desc_t *md)
+                                      efi_memory_desc_t *md,
+                                      bool ignored)
 {
        unsigned long base, size;
 
@@ -71,7 +72,7 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
         * If stricter permissions were specified, apply them now.
         */
        if (md->attribute & (EFI_MEMORY_RO | EFI_MEMORY_XP))
-               return efi_set_mapping_permissions(mm, md);
+               return efi_set_mapping_permissions(mm, md, false);
        return 0;
 }
 
index 31d13a6001df49c482a6bd426d0a8718288746ad..5d47d429672b1bfb6616d4bf256dea318331196b 100644 (file)
@@ -27,7 +27,8 @@ bool efi_runtime_fixup_exception(struct pt_regs *regs, const char *msg)
 #endif
 
 int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
-int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
+int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md,
+                               bool has_bti);
 
 #define arch_efi_call_virt_setup()                                     \
 ({                                                                     \
index fab05de2e12dd5d8ad28b1a647fea66c6ac1651e..78ffd5aaddcbbaeed3db47fe4366a85c345357c1 100644 (file)
@@ -110,7 +110,8 @@ static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data)
 }
 
 int __init efi_set_mapping_permissions(struct mm_struct *mm,
-                                      efi_memory_desc_t *md)
+                                      efi_memory_desc_t *md,
+                                      bool has_bti)
 {
        BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
               md->type != EFI_RUNTIME_SERVICES_DATA);
index 47d3ab0fcc36a186e43f816e8ed22d82965f6d98..29e9a0d84b16682f8a73d23573ee9b14179c99be 100644 (file)
@@ -19,7 +19,7 @@ extern void efi_init(void);
 #endif
 
 int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
-int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
+int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md, bool);
 
 #define arch_efi_call_virt_setup()      ({             \
                sync_kernel_mappings(efi_mm.pgd);       \
index 1aa540350abd31b077f10660f7862aa77e4c819c..aa6209a74c83ffc29f8622277196b799ebdd4321 100644 (file)
@@ -78,7 +78,8 @@ static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data)
 }
 
 int __init efi_set_mapping_permissions(struct mm_struct *mm,
-                                      efi_memory_desc_t *md)
+                                      efi_memory_desc_t *md,
+                                      bool ignored)
 {
        BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
               md->type != EFI_RUNTIME_SERVICES_DATA);
index b36596bf0fc38f4fbf907f5c19147425a2a4360d..2e6fe430cb07bbbc5fd8f3c25397041bc056a495 100644 (file)
@@ -389,7 +389,8 @@ static int __init efi_update_mappings(efi_memory_desc_t *md, unsigned long pf)
        return err1 || err2;
 }
 
-static int __init efi_update_mem_attr(struct mm_struct *mm, efi_memory_desc_t *md)
+static int __init efi_update_mem_attr(struct mm_struct *mm, efi_memory_desc_t *md,
+                                     bool has_ibt)
 {
        unsigned long pf = 0;
 
index 0a9aba5f9ceff0bff6c4507382afe487378afcd1..3cbf00f04c5b60ca9b2c3ad211ac828065b6d8a1 100644 (file)
@@ -129,6 +129,7 @@ int __init efi_memattr_apply_permissions(struct mm_struct *mm,
                                         efi_memattr_perm_setter fn)
 {
        efi_memory_attributes_table_t *tbl;
+       bool has_bti = false;
        int i, ret;
 
        if (tbl_size <= sizeof(*tbl))
@@ -150,6 +151,10 @@ int __init efi_memattr_apply_permissions(struct mm_struct *mm,
                return -ENOMEM;
        }
 
+       if (tbl->version > 1 &&
+           (tbl->flags & EFI_MEMORY_ATTRIBUTES_FLAGS_RT_FORWARD_CONTROL_FLOW_GUARD))
+               has_bti = true;
+
        if (efi_enabled(EFI_DBG))
                pr_info("Processing EFI Memory Attributes table:\n");
 
@@ -169,7 +174,7 @@ int __init efi_memattr_apply_permissions(struct mm_struct *mm,
                                efi_md_typeattr_format(buf, sizeof(buf), &md));
 
                if (valid) {
-                       ret = fn(mm, &md);
+                       ret = fn(mm, &md, has_bti);
                        if (ret)
                                pr_err("Error updating mappings, skipping subsequent md's\n");
                }
index 9d455d502ac92b653176b21cc5068a2a2115e36a..df88786b594717146f529d25e32ddf59ac880f3f 100644 (file)
@@ -584,11 +584,15 @@ typedef struct {
 
 #define EFI_INVALID_TABLE_ADDR         (~0UL)
 
+// BIT0 implies that Runtime code includes the forward control flow guard
+// instruction, such as X86 CET-IBT or ARM BTI.
+#define EFI_MEMORY_ATTRIBUTES_FLAGS_RT_FORWARD_CONTROL_FLOW_GUARD      0x1
+
 typedef struct {
        u32 version;
        u32 num_entries;
        u32 desc_size;
-       u32 reserved;
+       u32 flags;
        efi_memory_desc_t entry[0];
 } efi_memory_attributes_table_t;
 
@@ -751,7 +755,7 @@ extern unsigned long efi_mem_attr_table;
  *                           argument in the page tables referred to by the
  *                           first argument.
  */
-typedef int (*efi_memattr_perm_setter)(struct mm_struct *, efi_memory_desc_t *);
+typedef int (*efi_memattr_perm_setter)(struct mm_struct *, efi_memory_desc_t *, bool);
 
 extern int efi_memattr_init(void);
 extern int efi_memattr_apply_permissions(struct mm_struct *mm,