efi: x86: Wire up IBT annotation in memory attributes table
authorArd Biesheuvel <ardb@kernel.org>
Mon, 6 Feb 2023 12:33:07 +0000 (13:33 +0100)
committerArd Biesheuvel <ardb@kernel.org>
Thu, 9 Feb 2023 18:30:54 +0000 (19:30 +0100)
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>
arch/x86/include/asm/efi.h
arch/x86/include/asm/ibt.h
arch/x86/kernel/apm_32.c
arch/x86/kernel/cpu/common.c
arch/x86/platform/efi/efi_64.c

index cd19b9eca3f63cbd8e3a30842000820b86844ff4..9f8ded3de038197317d89cf4489ff9ce6ce465b2 100644 (file)
@@ -106,6 +106,8 @@ static inline void efi_fpu_end(void)
 
 extern asmlinkage u64 __efi_call(void *fp, ...);
 
+extern bool efi_disable_ibt_for_runtime;
+
 #define efi_call(...) ({                                               \
        __efi_nargs_check(efi_call, 7, __VA_ARGS__);                    \
        __efi_call(__VA_ARGS__);                                        \
@@ -121,7 +123,7 @@ extern asmlinkage u64 __efi_call(void *fp, ...);
 
 #undef arch_efi_call_virt
 #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);                             \
        ibt_restore(ibt);                                               \
        ret;                                                            \
index 9b08082a5d9f564bf3a765e9e52b2b4db9866de5..baae6b4fea23ae84ceb0550bd0ccdcaeb33bb305 100644 (file)
@@ -74,7 +74,7 @@ static inline bool is_endbr(u32 val)
        return val == gen_endbr();
 }
 
-extern __noendbr u64 ibt_save(void);
+extern __noendbr u64 ibt_save(bool disable);
 extern __noendbr void ibt_restore(u64 save);
 
 #else /* __ASSEMBLY__ */
@@ -100,7 +100,7 @@ extern __noendbr void ibt_restore(u64 save);
 
 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) { }
 
 #else /* __ASSEMBLY__ */
index 60e330cdbd1756481c89683bde6c8646cef81f3c..c6c15ce1952fb62ee9681c516e0c72c091461487 100644 (file)
@@ -609,7 +609,7 @@ static long __apm_bios_call(void *_call)
 
        apm_irq_save(flags);
        firmware_restrict_branch_speculation_start();
-       ibt = ibt_save();
+       ibt = ibt_save(true);
        APM_DO_SAVE_SEGS;
        apm_bios_call_asm(call->func, call->ebx, call->ecx,
                          &call->eax, &call->ebx, &call->ecx, &call->edx,
@@ -690,7 +690,7 @@ static long __apm_bios_call_simple(void *_call)
 
        apm_irq_save(flags);
        firmware_restrict_branch_speculation_start();
-       ibt = ibt_save();
+       ibt = ibt_save(true);
        APM_DO_SAVE_SEGS;
        error = apm_bios_call_simple_asm(call->func, call->ebx, call->ecx,
                                         &call->eax);
index 9cfca3d7d0e207c518b7cadf192a0f1337f790d6..54b246414eebb7b926f13f307c96d2f4f9d86f9a 100644 (file)
@@ -571,13 +571,14 @@ __setup("nopku", setup_disable_pku);
 
 #ifdef CONFIG_X86_KERNEL_IBT
 
-__noendbr u64 ibt_save(void)
+__noendbr u64 ibt_save(bool disable)
 {
        u64 msr = 0;
 
        if (cpu_feature_enabled(X86_FEATURE_IBT)) {
                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;
index 2e6fe430cb07bbbc5fd8f3c25397041bc056a495..232acf418cfbe625b5a5a427bf06ad26a05396ac 100644 (file)
@@ -389,11 +389,15 @@ static int __init efi_update_mappings(efi_memory_desc_t *md, unsigned long pf)
        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,
                                      bool has_ibt)
 {
        unsigned long pf = 0;
 
+       efi_disable_ibt_for_runtime |= !has_ibt;
+
        if (md->attribute & EFI_MEMORY_XP)
                pf |= _PAGE_NX;
 
@@ -415,6 +419,7 @@ void __init efi_runtime_update_mappings(void)
         * exists, since it is intended to supersede EFI_PROPERTIES_TABLE.
         */
        if (efi_enabled(EFI_MEM_ATTR)) {
+               efi_disable_ibt_for_runtime = false;
                efi_memattr_apply_permissions(NULL, efi_update_mem_attr);
                return;
        }