efi: Discover BTI support in runtime services regions

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>
This commit is contained in:
Ard Biesheuvel 2023-02-01 09:48:12 +01:00
parent b0048092f7
commit cf1d2ffcc6
9 changed files with 25 additions and 11 deletions

View 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()

View 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;
}

View 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() \
({ \

View 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);

View 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); \

View 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);

View 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;

View 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");
}

View 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,