lkml.org 
[lkml]   [2022]   [Mar]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[tip: x86/core] x86/ibt: Disable IBT around firmware
    The following commit has been merged into the x86/core branch of tip:

    Commit-ID: 80b6c49877883e5561ec3ecd2a5dd9d0f301eeaf
    Gitweb: https://git.kernel.org/tip/80b6c49877883e5561ec3ecd2a5dd9d0f301eeaf
    Author: Peter Zijlstra <peterz@infradead.org>
    AuthorDate: Tue, 08 Mar 2022 16:30:38 +01:00
    Committer: Peter Zijlstra <peterz@infradead.org>
    CommitterDate: Tue, 08 Mar 2022 23:53:34 +01:00

    x86/ibt: Disable IBT around firmware

    Assume firmware isn't IBT clean and disable it across calls.

    Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
    Reviewed-by: Kees Cook <keescook@chromium.org>
    Acked-by: Josh Poimboeuf <jpoimboe@redhat.com>
    Link: https://lore.kernel.org/r/20220308154318.759989383@infradead.org
    ---
    arch/x86/include/asm/efi.h | 9 +++++++--
    arch/x86/include/asm/ibt.h | 6 ++++++
    arch/x86/kernel/apm_32.c | 7 +++++++
    arch/x86/kernel/cpu/common.c | 28 ++++++++++++++++++++++++++++
    4 files changed, 48 insertions(+), 2 deletions(-)

    diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
    index 03cb127..98938a6 100644
    --- a/arch/x86/include/asm/efi.h
    +++ b/arch/x86/include/asm/efi.h
    @@ -7,6 +7,7 @@
    #include <asm/tlb.h>
    #include <asm/nospec-branch.h>
    #include <asm/mmu_context.h>
    +#include <asm/ibt.h>
    #include <linux/build_bug.h>
    #include <linux/kernel.h>
    #include <linux/pgtable.h>
    @@ -120,8 +121,12 @@ extern asmlinkage u64 __efi_call(void *fp, ...);
    efi_enter_mm(); \
    })

    -#define arch_efi_call_virt(p, f, args...) \
    - efi_call((void *)p->f, args) \
    +#define arch_efi_call_virt(p, f, args...) ({ \
    + u64 ret, ibt = ibt_save(); \
    + ret = efi_call((void *)p->f, args); \
    + ibt_restore(ibt); \
    + ret; \
    +})

    #define arch_efi_call_virt_teardown() \
    ({ \
    diff --git a/arch/x86/include/asm/ibt.h b/arch/x86/include/asm/ibt.h
    index fcaf6a4..52fb05d 100644
    --- a/arch/x86/include/asm/ibt.h
    +++ b/arch/x86/include/asm/ibt.h
    @@ -52,6 +52,9 @@ static inline bool is_endbr(u32 val)
    return val == gen_endbr();
    }

    +extern __noendbr u64 ibt_save(void);
    +extern __noendbr void ibt_restore(u64 save);
    +
    #else /* __ASSEMBLY__ */

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

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

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

    #define ENDBR
    diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
    index 241dda6..60e330c 100644
    --- a/arch/x86/kernel/apm_32.c
    +++ b/arch/x86/kernel/apm_32.c
    @@ -232,6 +232,7 @@
    #include <asm/paravirt.h>
    #include <asm/reboot.h>
    #include <asm/nospec-branch.h>
    +#include <asm/ibt.h>

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

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

    apm_irq_save(flags);
    firmware_restrict_branch_speculation_start();
    + ibt = ibt_save();
    APM_DO_SAVE_SEGS;
    apm_bios_call_asm(call->func, call->ebx, call->ecx,
    &call->eax, &call->ebx, &call->ecx, &call->edx,
    &call->esi);
    APM_DO_RESTORE_SEGS;
    + ibt_restore(ibt);
    firmware_restrict_branch_speculation_end();
    apm_irq_restore(flags);
    gdt[0x40 / 8] = save_desc_40;
    @@ -676,6 +680,7 @@ static long __apm_bios_call_simple(void *_call)
    struct desc_struct save_desc_40;
    struct desc_struct *gdt;
    struct apm_bios_call *call = _call;
    + u64 ibt;

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

    apm_irq_save(flags);
    firmware_restrict_branch_speculation_start();
    + ibt = ibt_save();
    APM_DO_SAVE_SEGS;
    error = apm_bios_call_simple_asm(call->func, call->ebx, call->ecx,
    &call->eax);
    APM_DO_RESTORE_SEGS;
    + ibt_restore(ibt);
    firmware_restrict_branch_speculation_end();
    apm_irq_restore(flags);
    gdt[0x40 / 8] = save_desc_40;
    diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
    index 709acab..03bd73f 100644
    --- a/arch/x86/kernel/cpu/common.c
    +++ b/arch/x86/kernel/cpu/common.c
    @@ -517,6 +517,34 @@ static __init int setup_disable_pku(char *arg)
    __setup("nopku", setup_disable_pku);
    #endif /* CONFIG_X86_64 */

    +#ifdef CONFIG_X86_KERNEL_IBT
    +
    +__noendbr u64 ibt_save(void)
    +{
    + 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);
    + }
    +
    + return msr;
    +}
    +
    +__noendbr void ibt_restore(u64 save)
    +{
    + u64 msr;
    +
    + if (cpu_feature_enabled(X86_FEATURE_IBT)) {
    + rdmsrl(MSR_IA32_S_CET, msr);
    + msr &= ~CET_ENDBR_EN;
    + msr |= (save & CET_ENDBR_EN);
    + wrmsrl(MSR_IA32_S_CET, msr);
    + }
    +}
    +
    +#endif
    +
    static __always_inline void setup_cet(struct cpuinfo_x86 *c)
    {
    u64 msr = CET_ENDBR_EN;
    \
     
     \ /
      Last update: 2022-03-09 08:56    [W:14.300 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site