From 8d8559ec66e8103e04f27b8d95ba6c83c103eb28 Mon Sep 17 00:00:00 2001 From: Tim Chen Date: Mon, 20 Nov 2017 13:47:54 -0800 Subject: [PATCH] x86/spec_ctrl: Add lock to serialize changes to ibrs and ibpb control Orabug: 27344012 CVE: CVE-2017-5715 Signed-off-by: Tim Chen Signed-off-by: Konrad Rzeszutek Wilk Reviewed-by: John Haxby Signed-off-by: Kirtikar Kashyap --- arch/x86/kernel/cpu/intel.c | 23 ++++++++++++----------- include/linux/smp.h | 1 + kernel/smp.c | 4 ++++ kernel/sysctl.c | 14 +++++++++++++- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 3d8b1170b3ab..f7c0167db1f7 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -494,17 +494,18 @@ static void init_intel(struct cpuinfo_x86 *c) } } - if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) { - printk_once(KERN_INFO "FEATURE SPEC_CTRL Present\n"); - set_ibrs_supported(); - set_ibpb_supported(); - if (ibrs_inuse) - sysctl_ibrs_enabled = 1; - if (ibpb_inuse) - sysctl_ibpb_enabled = 1; - } - else { - printk_once(KERN_INFO "FEATURE SPEC_CTRL Not Present\n"); + if (!c->cpu_index) { + if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) { + printk(KERN_INFO "FEATURE SPEC_CTRL Present\n"); + set_ibrs_supported(); + set_ibpb_supported(); + if (ibrs_inuse) + sysctl_ibrs_enabled = 1; + if (ibpb_inuse) + sysctl_ibpb_enabled = 1; + } else { + printk(KERN_INFO "FEATURE SPEC_CTRL Not Present\n"); + } } } diff --git a/include/linux/smp.h b/include/linux/smp.h index c340e38a6656..3689de249d0c 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -54,6 +54,7 @@ int smp_call_function_single_async(int cpu, struct call_single_data *csd); /* indicate usage of IBRS to control execution speculation */ extern int use_ibrs; extern u32 sysctl_ibrs_enabled; +extern struct mutex spec_ctrl_mutex; #define ibrs_supported (use_ibrs & 0x2) #define ibrs_disabled (use_ibrs & 0x4) static inline void set_ibrs_inuse(void) diff --git a/kernel/smp.c b/kernel/smp.c index 8db57e98cd2d..d71ad2deb805 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -518,6 +518,10 @@ EXPORT_SYMBOL(use_ibrs); int use_ibpb; EXPORT_SYMBOL(use_ibpb); +/* mutex to serialize IBRS & IBPB control changes */ +DEFINE_MUTEX(spec_ctrl_mutex); +EXPORT_SYMBOL(spec_ctrl_mutex); + /* * Setup routine for controlling SMP activation * diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 60726ece3bf2..857f1fd3c16a 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include @@ -2844,12 +2845,17 @@ int proc_do_large_bitmap(struct ctl_table *table, int write, int proc_dointvec_ibrs_dump(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - int ret; + int ret, orig_inuse; unsigned int cpu; + ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); printk("sysctl_ibrs_enabled = %u, sysctl_ibpb_enabled = %u\n", sysctl_ibrs_enabled, sysctl_ibpb_enabled); printk("use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb); + mutex_lock(&spec_ctrl_mutex); + orig_inuse = use_ibrs; + /* temporary halt to ibrs usage to dump ibrs values */ + clear_ibrs_inuse(); for_each_online_cpu(cpu) { u64 val; @@ -2859,6 +2865,8 @@ int proc_dointvec_ibrs_dump(struct ctl_table *table, int write, val = 0; printk("read cpu %d ibrs val %lu\n", cpu, (unsigned long) val); } + use_ibrs = orig_inuse; + mutex_unlock(&spec_ctrl_mutex); return ret; } @@ -2871,6 +2879,7 @@ int proc_dointvec_ibrs_ctrl(struct ctl_table *table, int write, ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); pr_debug("sysctl_ibrs_enabled = %u, sysctl_ibpb_enabled = %u\n", sysctl_ibrs_enabled, sysctl_ibpb_enabled); pr_debug("before:use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb); + mutex_lock(&spec_ctrl_mutex); if (sysctl_ibrs_enabled == 0) { /* always set IBRS off */ set_ibrs_disabled(); @@ -2894,6 +2903,7 @@ int proc_dointvec_ibrs_ctrl(struct ctl_table *table, int write, /* platform don't support ibrs */ sysctl_ibrs_enabled = 0; } + mutex_unlock(&spec_ctrl_mutex); pr_debug("after:use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb); return ret; } @@ -2906,6 +2916,7 @@ int proc_dointvec_ibpb_ctrl(struct ctl_table *table, int write, ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); pr_debug("sysctl_ibrs_enabled = %u, sysctl_ibpb_enabled = %u\n", sysctl_ibrs_enabled, sysctl_ibpb_enabled); pr_debug("before:use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb); + mutex_lock(&spec_ctrl_mutex); if (sysctl_ibpb_enabled == 0) set_ibpb_disabled(); else if (sysctl_ibpb_enabled == 1) { @@ -2914,6 +2925,7 @@ int proc_dointvec_ibpb_ctrl(struct ctl_table *table, int write, /* platform don't support ibpb */ sysctl_ibpb_enabled = 0; } + mutex_unlock(&spec_ctrl_mutex); pr_debug("after:use_ibrs = %d, use_ibpb = %d\n", use_ibrs, use_ibpb); return ret; } -- 2.50.1