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 b95241b..78282ce 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 882104f..e2b9d26 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 31d13a6..5d47d42 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 fab05de..78ffd5a 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 47d3ab0..29e9a0d 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 1aa5403..aa6209a 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 b36596b..2e6fe43 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 0a9aba5..3cbf00f 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 9d455d5..df88786 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,