efi: x86: Wire up IBT annotation in memory attributes table

UEFI v2.10 extends the EFI memory attributes table with a flag that
indicates whether or not all RuntimeServicesCode regions were
constructed with ENDBR landing pads, permitting the OS to map these
regions with IBT restrictions enabled.

So let's take this into account on x86 as well.

Suggested-by: Peter Zijlstra <peterz@infradead.org> # ibt_save() changes
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
This commit is contained in:
Ard Biesheuvel 2023-02-06 13:33:07 +01:00
parent 1d959312e2
commit 93be2859e2
5 changed files with 15 additions and 7 deletions

View File

@ -106,6 +106,8 @@ static inline void efi_fpu_end(void)
extern asmlinkage u64 __efi_call(void *fp, ...); extern asmlinkage u64 __efi_call(void *fp, ...);
extern bool efi_disable_ibt_for_runtime;
#define efi_call(...) ({ \ #define efi_call(...) ({ \
__efi_nargs_check(efi_call, 7, __VA_ARGS__); \ __efi_nargs_check(efi_call, 7, __VA_ARGS__); \
__efi_call(__VA_ARGS__); \ __efi_call(__VA_ARGS__); \
@ -121,7 +123,7 @@ extern asmlinkage u64 __efi_call(void *fp, ...);
#undef arch_efi_call_virt #undef arch_efi_call_virt
#define arch_efi_call_virt(p, f, args...) ({ \ #define arch_efi_call_virt(p, f, args...) ({ \
u64 ret, ibt = ibt_save(); \ u64 ret, ibt = ibt_save(efi_disable_ibt_for_runtime); \
ret = efi_call((void *)p->f, args); \ ret = efi_call((void *)p->f, args); \
ibt_restore(ibt); \ ibt_restore(ibt); \
ret; \ ret; \

View File

@ -74,7 +74,7 @@ static inline bool is_endbr(u32 val)
return val == gen_endbr(); return val == gen_endbr();
} }
extern __noendbr u64 ibt_save(void); extern __noendbr u64 ibt_save(bool disable);
extern __noendbr void ibt_restore(u64 save); extern __noendbr void ibt_restore(u64 save);
#else /* __ASSEMBLY__ */ #else /* __ASSEMBLY__ */
@ -100,7 +100,7 @@ extern __noendbr void ibt_restore(u64 save);
static inline bool is_endbr(u32 val) { return false; } static inline bool is_endbr(u32 val) { return false; }
static inline u64 ibt_save(void) { return 0; } static inline u64 ibt_save(bool disable) { return 0; }
static inline void ibt_restore(u64 save) { } static inline void ibt_restore(u64 save) { }
#else /* __ASSEMBLY__ */ #else /* __ASSEMBLY__ */

View File

@ -609,7 +609,7 @@ static long __apm_bios_call(void *_call)
apm_irq_save(flags); apm_irq_save(flags);
firmware_restrict_branch_speculation_start(); firmware_restrict_branch_speculation_start();
ibt = ibt_save(); ibt = ibt_save(true);
APM_DO_SAVE_SEGS; APM_DO_SAVE_SEGS;
apm_bios_call_asm(call->func, call->ebx, call->ecx, apm_bios_call_asm(call->func, call->ebx, call->ecx,
&call->eax, &call->ebx, &call->ecx, &call->edx, &call->eax, &call->ebx, &call->ecx, &call->edx,
@ -690,7 +690,7 @@ static long __apm_bios_call_simple(void *_call)
apm_irq_save(flags); apm_irq_save(flags);
firmware_restrict_branch_speculation_start(); firmware_restrict_branch_speculation_start();
ibt = ibt_save(); ibt = ibt_save(true);
APM_DO_SAVE_SEGS; APM_DO_SAVE_SEGS;
error = apm_bios_call_simple_asm(call->func, call->ebx, call->ecx, error = apm_bios_call_simple_asm(call->func, call->ebx, call->ecx,
&call->eax); &call->eax);

View File

@ -571,13 +571,14 @@ __setup("nopku", setup_disable_pku);
#ifdef CONFIG_X86_KERNEL_IBT #ifdef CONFIG_X86_KERNEL_IBT
__noendbr u64 ibt_save(void) __noendbr u64 ibt_save(bool disable)
{ {
u64 msr = 0; u64 msr = 0;
if (cpu_feature_enabled(X86_FEATURE_IBT)) { if (cpu_feature_enabled(X86_FEATURE_IBT)) {
rdmsrl(MSR_IA32_S_CET, msr); rdmsrl(MSR_IA32_S_CET, msr);
wrmsrl(MSR_IA32_S_CET, msr & ~CET_ENDBR_EN); if (disable)
wrmsrl(MSR_IA32_S_CET, msr & ~CET_ENDBR_EN);
} }
return msr; return msr;

View File

@ -389,11 +389,15 @@ static int __init efi_update_mappings(efi_memory_desc_t *md, unsigned long pf)
return err1 || err2; return err1 || err2;
} }
bool efi_disable_ibt_for_runtime __ro_after_init = true;
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) bool has_ibt)
{ {
unsigned long pf = 0; unsigned long pf = 0;
efi_disable_ibt_for_runtime |= !has_ibt;
if (md->attribute & EFI_MEMORY_XP) if (md->attribute & EFI_MEMORY_XP)
pf |= _PAGE_NX; pf |= _PAGE_NX;
@ -415,6 +419,7 @@ void __init efi_runtime_update_mappings(void)
* exists, since it is intended to supersede EFI_PROPERTIES_TABLE. * exists, since it is intended to supersede EFI_PROPERTIES_TABLE.
*/ */
if (efi_enabled(EFI_MEM_ATTR)) { if (efi_enabled(EFI_MEM_ATTR)) {
efi_disable_ibt_for_runtime = false;
efi_memattr_apply_permissions(NULL, efi_update_mem_attr); efi_memattr_apply_permissions(NULL, efi_update_mem_attr);
return; return;
} }