Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit fe379fa

Browse files
author
Peter Zijlstra
committed
x86/ibt: Disable IBT around firmware
Assume firmware isn't IBT clean and disable it across calls. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Kees Cook <[email protected]> Acked-by: Josh Poimboeuf <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 99c95c5 commit fe379fa

File tree

4 files changed

+48
-2
lines changed

4 files changed

+48
-2
lines changed

arch/x86/include/asm/efi.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <asm/tlb.h>
88
#include <asm/nospec-branch.h>
99
#include <asm/mmu_context.h>
10+
#include <asm/ibt.h>
1011
#include <linux/build_bug.h>
1112
#include <linux/kernel.h>
1213
#include <linux/pgtable.h>
@@ -120,8 +121,12 @@ extern asmlinkage u64 __efi_call(void *fp, ...);
120121
efi_enter_mm(); \
121122
})
122123

123-
#define arch_efi_call_virt(p, f, args...) \
124-
efi_call((void *)p->f, args) \
124+
#define arch_efi_call_virt(p, f, args...) ({ \
125+
u64 ret, ibt = ibt_save(); \
126+
ret = efi_call((void *)p->f, args); \
127+
ibt_restore(ibt); \
128+
ret; \
129+
})
125130

126131
#define arch_efi_call_virt_teardown() \
127132
({ \

arch/x86/include/asm/ibt.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ static inline bool is_endbr(u32 val)
5252
return val == gen_endbr();
5353
}
5454

55+
extern __noendbr u64 ibt_save(void);
56+
extern __noendbr void ibt_restore(u64 save);
57+
5558
#else /* __ASSEMBLY__ */
5659

5760
#ifdef CONFIG_X86_64
@@ -74,6 +77,9 @@ static inline bool is_endbr(u32 val)
7477

7578
static inline bool is_endbr(u32 val) { return false; }
7679

80+
static inline u64 ibt_save(void) { return 0; }
81+
static inline void ibt_restore(u64 save) { }
82+
7783
#else /* __ASSEMBLY__ */
7884

7985
#define ENDBR

arch/x86/kernel/apm_32.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@
232232
#include <asm/paravirt.h>
233233
#include <asm/reboot.h>
234234
#include <asm/nospec-branch.h>
235+
#include <asm/ibt.h>
235236

236237
#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
237238
extern int (*console_blank_hook)(int);
@@ -598,6 +599,7 @@ static long __apm_bios_call(void *_call)
598599
struct desc_struct save_desc_40;
599600
struct desc_struct *gdt;
600601
struct apm_bios_call *call = _call;
602+
u64 ibt;
601603

602604
cpu = get_cpu();
603605
BUG_ON(cpu != 0);
@@ -607,11 +609,13 @@ static long __apm_bios_call(void *_call)
607609

608610
apm_irq_save(flags);
609611
firmware_restrict_branch_speculation_start();
612+
ibt = ibt_save();
610613
APM_DO_SAVE_SEGS;
611614
apm_bios_call_asm(call->func, call->ebx, call->ecx,
612615
&call->eax, &call->ebx, &call->ecx, &call->edx,
613616
&call->esi);
614617
APM_DO_RESTORE_SEGS;
618+
ibt_restore(ibt);
615619
firmware_restrict_branch_speculation_end();
616620
apm_irq_restore(flags);
617621
gdt[0x40 / 8] = save_desc_40;
@@ -676,6 +680,7 @@ static long __apm_bios_call_simple(void *_call)
676680
struct desc_struct save_desc_40;
677681
struct desc_struct *gdt;
678682
struct apm_bios_call *call = _call;
683+
u64 ibt;
679684

680685
cpu = get_cpu();
681686
BUG_ON(cpu != 0);
@@ -685,10 +690,12 @@ static long __apm_bios_call_simple(void *_call)
685690

686691
apm_irq_save(flags);
687692
firmware_restrict_branch_speculation_start();
693+
ibt = ibt_save();
688694
APM_DO_SAVE_SEGS;
689695
error = apm_bios_call_simple_asm(call->func, call->ebx, call->ecx,
690696
&call->eax);
691697
APM_DO_RESTORE_SEGS;
698+
ibt_restore(ibt);
692699
firmware_restrict_branch_speculation_end();
693700
apm_irq_restore(flags);
694701
gdt[0x40 / 8] = save_desc_40;

arch/x86/kernel/cpu/common.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,34 @@ static __init int setup_disable_pku(char *arg)
517517
__setup("nopku", setup_disable_pku);
518518
#endif /* CONFIG_X86_64 */
519519

520+
#ifdef CONFIG_X86_KERNEL_IBT
521+
522+
__noendbr u64 ibt_save(void)
523+
{
524+
u64 msr = 0;
525+
526+
if (cpu_feature_enabled(X86_FEATURE_IBT)) {
527+
rdmsrl(MSR_IA32_S_CET, msr);
528+
wrmsrl(MSR_IA32_S_CET, msr & ~CET_ENDBR_EN);
529+
}
530+
531+
return msr;
532+
}
533+
534+
__noendbr void ibt_restore(u64 save)
535+
{
536+
u64 msr;
537+
538+
if (cpu_feature_enabled(X86_FEATURE_IBT)) {
539+
rdmsrl(MSR_IA32_S_CET, msr);
540+
msr &= ~CET_ENDBR_EN;
541+
msr |= (save & CET_ENDBR_EN);
542+
wrmsrl(MSR_IA32_S_CET, msr);
543+
}
544+
}
545+
546+
#endif
547+
520548
static __always_inline void setup_cet(struct cpuinfo_x86 *c)
521549
{
522550
u64 msr = CET_ENDBR_EN;

0 commit comments

Comments
 (0)