Skip to content

Commit

Permalink
x86/ibt: Add IBT feature, MSR and #CP handling
Browse files Browse the repository at this point in the history
The bits required to make the hardware go.. Of note is that, provided
the syscall entry points are covered with ENDBR, #CP doesn't need to
be an IST because we'll never hit the syscall gap.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lore.kernel.org/r/20220308154318.582331711@infradead.org
  • Loading branch information
Peter Zijlstra committed Mar 15, 2022
1 parent 0aec21c commit 991625f
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 2 deletions.
1 change: 1 addition & 0 deletions arch/x86/include/asm/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <linux/topology.h>
#include <linux/nodemask.h>
#include <linux/percpu.h>
#include <asm/ibt.h>

#ifdef CONFIG_SMP

Expand Down
1 change: 1 addition & 0 deletions arch/x86/include/asm/cpufeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@
#define X86_FEATURE_TSXLDTRK (18*32+16) /* TSX Suspend Load Address Tracking */
#define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */
#define X86_FEATURE_ARCH_LBR (18*32+19) /* Intel ARCH LBR */
#define X86_FEATURE_IBT (18*32+20) /* Indirect Branch Tracking */
#define X86_FEATURE_AVX512_FP16 (18*32+23) /* AVX512 FP16 */
#define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */
#define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */
Expand Down
5 changes: 5 additions & 0 deletions arch/x86/include/asm/idtentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,11 @@ DECLARE_IDTENTRY_DF(X86_TRAP_DF, exc_double_fault);
DECLARE_IDTENTRY_RAW_ERRORCODE(X86_TRAP_DF, xenpv_exc_double_fault);
#endif

/* #CP */
#ifdef CONFIG_X86_KERNEL_IBT
DECLARE_IDTENTRY_ERRORCODE(X86_TRAP_CP, exc_control_protection);
#endif

/* #VC */
#ifdef CONFIG_AMD_MEM_ENCRYPT
DECLARE_IDTENTRY_VC(X86_TRAP_VC, exc_vmm_communication);
Expand Down
20 changes: 19 additions & 1 deletion arch/x86/include/asm/msr-index.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,11 +360,29 @@
#define MSR_ATOM_CORE_TURBO_RATIOS 0x0000066c
#define MSR_ATOM_CORE_TURBO_VIDS 0x0000066d


#define MSR_CORE_PERF_LIMIT_REASONS 0x00000690
#define MSR_GFX_PERF_LIMIT_REASONS 0x000006B0
#define MSR_RING_PERF_LIMIT_REASONS 0x000006B1

/* Control-flow Enforcement Technology MSRs */
#define MSR_IA32_U_CET 0x000006a0 /* user mode cet */
#define MSR_IA32_S_CET 0x000006a2 /* kernel mode cet */
#define CET_SHSTK_EN BIT_ULL(0)
#define CET_WRSS_EN BIT_ULL(1)
#define CET_ENDBR_EN BIT_ULL(2)
#define CET_LEG_IW_EN BIT_ULL(3)
#define CET_NO_TRACK_EN BIT_ULL(4)
#define CET_SUPPRESS_DISABLE BIT_ULL(5)
#define CET_RESERVED (BIT_ULL(6) | BIT_ULL(7) | BIT_ULL(8) | BIT_ULL(9))
#define CET_SUPPRESS BIT_ULL(10)
#define CET_WAIT_ENDBR BIT_ULL(11)

#define MSR_IA32_PL0_SSP 0x000006a4 /* ring-0 shadow stack pointer */
#define MSR_IA32_PL1_SSP 0x000006a5 /* ring-1 shadow stack pointer */
#define MSR_IA32_PL2_SSP 0x000006a6 /* ring-2 shadow stack pointer */
#define MSR_IA32_PL3_SSP 0x000006a7 /* ring-3 shadow stack pointer */
#define MSR_IA32_INT_SSP_TAB 0x000006a8 /* exception shadow stack table */

/* Hardware P state interface */
#define MSR_PPERF 0x0000064e
#define MSR_PERF_LIMIT_REASONS 0x0000064f
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/include/asm/traps.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ void __init trap_init(void);
asmlinkage __visible noinstr struct pt_regs *vc_switch_off_ist(struct pt_regs *eregs);
#endif

extern bool ibt_selftest(void);

#ifdef CONFIG_X86_F00F_BUG
/* For handling the FOOF bug */
void handle_invalid_op(struct pt_regs *regs);
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/include/uapi/asm/processor-flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@
#define X86_CR4_SMAP _BITUL(X86_CR4_SMAP_BIT)
#define X86_CR4_PKE_BIT 22 /* enable Protection Keys support */
#define X86_CR4_PKE _BITUL(X86_CR4_PKE_BIT)
#define X86_CR4_CET_BIT 23 /* enable Control-flow Enforcement Technology */
#define X86_CR4_CET _BITUL(X86_CR4_CET_BIT)

/*
* x86-64 Task Priority Register, CR8
Expand Down
25 changes: 24 additions & 1 deletion arch/x86/kernel/cpu/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
#include <asm/cpu_device_id.h>
#include <asm/uv/uv.h>
#include <asm/sigframe.h>
#include <asm/traps.h>

#include "cpu.h"

Expand Down Expand Up @@ -361,7 +362,8 @@ static __always_inline void setup_umip(struct cpuinfo_x86 *c)

/* These bits should not change their value after CPU init is finished. */
static const unsigned long cr4_pinned_mask =
X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP | X86_CR4_FSGSBASE;
X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP |
X86_CR4_FSGSBASE | X86_CR4_CET;
static DEFINE_STATIC_KEY_FALSE_RO(cr_pinning);
static unsigned long cr4_pinned_bits __ro_after_init;

Expand Down Expand Up @@ -515,6 +517,24 @@ static __init int setup_disable_pku(char *arg)
__setup("nopku", setup_disable_pku);
#endif /* CONFIG_X86_64 */

static __always_inline void setup_cet(struct cpuinfo_x86 *c)
{
u64 msr = CET_ENDBR_EN;

if (!HAS_KERNEL_IBT ||
!cpu_feature_enabled(X86_FEATURE_IBT))
return;

wrmsrl(MSR_IA32_S_CET, msr);
cr4_set_bits(X86_CR4_CET);

if (!ibt_selftest()) {
pr_err("IBT selftest: Failed!\n");
setup_clear_cpu_cap(X86_FEATURE_IBT);
return;
}
}

/*
* Some CPU features depend on higher CPUID levels, which may not always
* be available due to CPUID level capping or broken virtualization
Expand Down Expand Up @@ -1632,6 +1652,7 @@ static void identify_cpu(struct cpuinfo_x86 *c)

x86_init_rdrand(c);
setup_pku(c);
setup_cet(c);

/*
* Clear/Set all flags overridden by options, need do it
Expand Down Expand Up @@ -1698,6 +1719,8 @@ void enable_sep_cpu(void)
void __init identify_boot_cpu(void)
{
identify_cpu(&boot_cpu_data);
if (HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT))
pr_info("CET detected: Indirect Branch Tracking enabled\n");
#ifdef CONFIG_X86_32
sysenter_setup();
enable_sep_cpu();
Expand Down
4 changes: 4 additions & 0 deletions arch/x86/kernel/idt.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ static const __initconst struct idt_data def_idts[] = {
ISTG(X86_TRAP_MC, asm_exc_machine_check, IST_INDEX_MCE),
#endif

#ifdef CONFIG_X86_KERNEL_IBT
INTG(X86_TRAP_CP, asm_exc_control_protection),
#endif

#ifdef CONFIG_AMD_MEM_ENCRYPT
ISTG(X86_TRAP_VC, asm_exc_vmm_communication, IST_INDEX_VC),
#endif
Expand Down
75 changes: 75 additions & 0 deletions arch/x86/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,81 @@ DEFINE_IDTENTRY(exc_overflow)
do_error_trap(regs, 0, "overflow", X86_TRAP_OF, SIGSEGV, 0, NULL);
}

#ifdef CONFIG_X86_KERNEL_IBT

static __ro_after_init bool ibt_fatal = true;

extern void ibt_selftest_ip(void); /* code label defined in asm below */

enum cp_error_code {
CP_EC = (1 << 15) - 1,

CP_RET = 1,
CP_IRET = 2,
CP_ENDBR = 3,
CP_RSTRORSSP = 4,
CP_SETSSBSY = 5,

CP_ENCL = 1 << 15,
};

DEFINE_IDTENTRY_ERRORCODE(exc_control_protection)
{
if (!cpu_feature_enabled(X86_FEATURE_IBT)) {
pr_err("Unexpected #CP\n");
BUG();
}

if (WARN_ON_ONCE(user_mode(regs) || (error_code & CP_EC) != CP_ENDBR))
return;

if (unlikely(regs->ip == (unsigned long)&ibt_selftest_ip)) {
regs->ax = 0;
return;
}

pr_err("Missing ENDBR: %pS\n", (void *)instruction_pointer(regs));
if (!ibt_fatal) {
printk(KERN_DEFAULT CUT_HERE);
__warn(__FILE__, __LINE__, (void *)regs->ip, TAINT_WARN, regs, NULL);
return;
}
BUG();
}

/* Must be noinline to ensure uniqueness of ibt_selftest_ip. */
noinline bool ibt_selftest(void)
{
unsigned long ret;

asm (" lea ibt_selftest_ip(%%rip), %%rax\n\t"
ANNOTATE_RETPOLINE_SAFE
" jmp *%%rax\n\t"
"ibt_selftest_ip:\n\t"
UNWIND_HINT_FUNC
ANNOTATE_NOENDBR
" nop\n\t"

: "=a" (ret) : : "memory");

return !ret;
}

static int __init ibt_setup(char *str)
{
if (!strcmp(str, "off"))
setup_clear_cpu_cap(X86_FEATURE_IBT);

if (!strcmp(str, "warn"))
ibt_fatal = false;

return 1;
}

__setup("ibt=", ibt_setup);

#endif /* CONFIG_X86_KERNEL_IBT */

#ifdef CONFIG_X86_F00F_BUG
void handle_invalid_op(struct pt_regs *regs)
#else
Expand Down

0 comments on commit 991625f

Please sign in to comment.