Commit 6d5aea6b authored by Juerg Haefliger's avatar Juerg Haefliger Committed by Kleber Sacilotto de Souza

UBUNTU: SAUCE: x86/speculation: Cleanup IBPB runtime control handling

In Ubuntu, we have runtime control for enabling/disabling IBPB via the
commandline ("noibpb") and through the proc interface
/proc/sys/kernel/ibpb_enabled. This commit simplifies the current
(broken) implementation by merging it with all the IBPB-related upstream
changes from previous commits.

What we have now is the upstream implementation for detecting the presence
of IBPB support which is used in the alternative MSR write in
indirect_branch_prediction_barrier() to enable IBPB. On top of that, this
commit adds a global state variable 'ibpb_enabled' which is set to 1 if
the CPU supports IBPB but can be overridden via the commandline "noibpb"
switch or by writting 0 or 1 to /proc/sys/kernel/ibpb_enabled at runtime.

If ibpb_enabled is 0, indirect_branch_prediction_barrier() is turned into a
no-op, same as if the platform doesn't support IBPB.

CVE-2017-5715
Signed-off-by: default avatarJuerg Haefliger <juergh@canonical.com>
Acked-by: default avatarStefan Bader <stefan.bader@canonical.com>
Acked-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent 10288d21
......@@ -184,6 +184,10 @@
# define THUNK_TARGET(addr) [thunk_target] "rm" (addr)
#endif
/* The IBPB runtime control knob */
extern unsigned int ibpb_enabled;
int set_ibpb_enabled(unsigned int);
/* The Spectre V2 mitigation variants */
enum spectre_v2_mitigation {
SPECTRE_V2_NONE,
......@@ -243,7 +247,9 @@ static inline void indirect_branch_prediction_barrier(void)
{
u64 val = PRED_CMD_IBPB;
alternative_msr_write(MSR_IA32_PRED_CMD, val, X86_FEATURE_USE_IBPB);
if (ibpb_enabled)
alternative_msr_write(MSR_IA32_PRED_CMD, val,
X86_FEATURE_USE_IBPB);
}
/*
......
......@@ -9,7 +9,6 @@
#ifdef __ASSEMBLY__
.extern use_ibrs
.extern use_ibpb
#define __ASM_ENABLE_IBRS \
pushq %rax; \
......
......@@ -21,6 +21,9 @@
#include "cpu.h"
/* "noibpb" commandline parameter present (1) or not (0) */
extern unsigned int noibpb;
/*
* nodes_per_socket: Stores the number of nodes per socket.
* Refer to Fam15h Models 00-0fh BKDG - CPUID Fn8000_001E_ECX
......@@ -842,7 +845,7 @@ static void init_amd(struct cpuinfo_x86 *c)
* speculative control features, IBPB type support can be achieved by
* disabling indirect branch predictor support.
*/
if (!ibpb_disabled && !cpu_has(c, X86_FEATURE_SPEC_CTRL) &&
if (!noibpb && !cpu_has(c, X86_FEATURE_SPEC_CTRL) &&
!cpu_has(c, X86_FEATURE_IBPB)) {
u64 val;
......
......@@ -30,6 +30,16 @@
#include <asm/intel-family.h>
#include <asm/e820.h>
unsigned int noibpb = 0;
static int __init noibpb_handler(char *str)
{
noibpb = 1;
return 0;
}
early_param("noibpb", noibpb_handler);
static void __init spectre_v2_select_mitigation(void);
static void __init ssb_select_mitigation(void);
static void __init l1tf_select_mitigation(void);
......@@ -390,14 +400,14 @@ static void __init spectre_v2_select_mitigation(void)
spectre_v2_enabled = mode;
pr_info("%s\n", spectre_v2_strings[mode]);
/* Initialize Indirect Branch Prediction Barrier if supported */
/*
* Initialize Indirect Branch Prediction Barrier if supported and not
* disabled on the commandline
*/
if (boot_cpu_has(X86_FEATURE_IBPB)) {
setup_force_cpu_cap(X86_FEATURE_USE_IBPB);
pr_info("Spectre v2 mitigation: Enabling Indirect Branch Prediction Barrier\n");
set_ibpb_supported();
if (ibpb_inuse)
sysctl_ibpb_enabled = 1;
if (!noibpb)
set_ibpb_enabled(1); /* Enable IBPB */
}
/* Initialize Indirect Branch Restricted Speculation if supported */
......@@ -409,8 +419,7 @@ static void __init spectre_v2_select_mitigation(void)
sysctl_ibrs_enabled = 1;
}
pr_info("Spectre v2 mitigation: Speculation control IBPB %s IBRS %s",
ibpb_supported ? "supported" : "not-supported",
pr_info("Spectre v2 mitigation: Speculation control IBRS %s",
ibrs_supported ? "supported" : "not-supported");
/*
......@@ -863,7 +872,7 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
case X86_BUG_SPECTRE_V2:
return sprintf(buf, "%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled],
ibpb_inuse ? ", IBPB (Intel v4)" : "",
ibpb_enabled ? ", IBPB" : "",
boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "",
spectre_v2_module_string());
......
......@@ -439,18 +439,6 @@ static ssize_t reload_store(struct device *dev,
if (!ret)
perf_check_microcode();
/* Initialize Indirect Branch Prediction Barrier if supported */
if (boot_cpu_has(X86_FEATURE_IBPB)) {
setup_force_cpu_cap(X86_FEATURE_USE_IBPB);
pr_info("Enabling Indirect Branch Prediction Barrier\n");
mutex_lock(&spec_ctrl_mutex);
set_ibpb_supported();
if (ibpb_inuse)
sysctl_ibpb_enabled = 1;
mutex_unlock(&spec_ctrl_mutex);
}
/* Initialize Indirect Branch Restricted Speculation if supported */
if (boot_cpu_has(X86_FEATURE_IBRS)) {
pr_info("Enabling Indirect Branch Restricted Speculation\n");
......
......@@ -1230,8 +1230,7 @@ static void svm_free_vcpu(struct kvm_vcpu *vcpu)
* The VMCB could be recycled, causing a false negative in svm_vcpu_load;
* block speculative execution.
*/
if (ibpb_inuse)
wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB);
indirect_branch_prediction_barrier();
}
static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
......@@ -1265,8 +1264,7 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
if (sd->current_vmcb != svm->vmcb) {
sd->current_vmcb = svm->vmcb;
if (ibpb_inuse)
wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB);
indirect_branch_prediction_barrier();
}
}
......
......@@ -2245,8 +2245,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
if (per_cpu(current_vmcs, cpu) != vmx->loaded_vmcs->vmcs) {
per_cpu(current_vmcs, cpu) = vmx->loaded_vmcs->vmcs;
vmcs_load(vmx->loaded_vmcs->vmcs);
if (ibpb_inuse)
native_wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB);
indirect_branch_prediction_barrier();
}
if (vmx->loaded_vmcs->cpu != cpu) {
......
......@@ -127,7 +127,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
*/
if (tsk && tsk->mm &&
tsk->mm->context.ctx_id != last_ctx_id &&
get_dumpable(tsk->mm) != SUID_DUMP_USER && ibpb_inuse)
get_dumpable(tsk->mm) != SUID_DUMP_USER)
indirect_branch_prediction_barrier();
/*
......
......@@ -94,43 +94,6 @@ static inline void clear_ibrs_disabled(void)
use_ibrs |= IBxx_INUSE;
}
/* indicate usage of IBPB to control execution speculation */
extern int use_ibpb;
extern u32 sysctl_ibpb_enabled;
static inline int __check_ibpb_inuse(void)
{
if (use_ibpb & IBxx_INUSE)
return 1;
else
/* rmb to prevent wrong speculation for security */
rmb();
return 0;
}
#define ibpb_inuse (__check_ibpb_inuse())
#define ibpb_supported (use_ibpb & IBxx_SUPPORTED)
#define ibpb_disabled (use_ibpb & IBxx_DISABLED)
static inline void set_ibpb_supported(void)
{
use_ibpb |= IBxx_SUPPORTED;
if (!ibpb_disabled)
use_ibpb |= IBxx_INUSE;
}
static inline void set_ibpb_disabled(void)
{
use_ibpb |= IBxx_DISABLED;
if (ibpb_inuse)
use_ibpb &= ~IBxx_INUSE;
}
static inline void clear_ibpb_disabled(void)
{
use_ibpb &= ~IBxx_DISABLED;
if (ibpb_supported)
use_ibpb |= IBxx_INUSE;
}
#endif /* CONFIG_X86 */
#ifdef CONFIG_SMP
......
......@@ -509,15 +509,6 @@ EXPORT_SYMBOL(setup_max_cpus);
int use_ibrs;
EXPORT_SYMBOL(use_ibrs);
/*
* use IBRS
* bit 0 = indicate if ibpb is currently in use
* bit 1 = indicate if system supports ibpb
* bit 2 = indicate if admin disables ibpb
*/
int use_ibpb;
EXPORT_SYMBOL(use_ibpb);
#endif
/* mutex to serialize IBRS & IBPB control changes */
......@@ -556,15 +547,6 @@ static int __init noibrs(char *str)
}
early_param("noibrs", noibrs);
static int __init noibpb(char *str)
{
set_ibpb_disabled();
return 0;
}
early_param("noibpb", noibpb);
#endif
......
......@@ -204,8 +204,54 @@ static int proc_dostring_coredump(struct ctl_table *table, int write,
#ifdef CONFIG_X86
int proc_dointvec_ibrs_ctrl(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos);
int proc_dointvec_ibpb_ctrl(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos);
unsigned int ibpb_enabled = 0;
EXPORT_SYMBOL(ibpb_enabled); /* Required in some modules */
static unsigned int __ibpb_enabled = 0; /* procfs shadow variable */
int set_ibpb_enabled(unsigned int val)
{
int error = 0;
unsigned int prev = ibpb_enabled;
mutex_lock(&spec_ctrl_mutex);
/* Only enable/disable IBPB if the CPU supports it */
if (boot_cpu_has(X86_FEATURE_USE_IBPB)) {
ibpb_enabled = val;
if (ibpb_enabled != prev)
pr_info("Spectre V2 : Spectre v2 mitigation: %s "
"Indirect Branch Prediction Barrier\n",
ibpb_enabled ? "Enabling" : "Disabling");
} else {
ibpb_enabled = 0;
if (val) {
/* IBPB is not supported but we try to turn it on */
error = -EINVAL;
}
}
/* Update the shadow variable */
__ibpb_enabled = ibpb_enabled;
mutex_unlock(&spec_ctrl_mutex);
return error;
}
static int ibpb_enabled_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
loff_t *ppos)
{
int error;
error = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
if (error)
return error;
return set_ibpb_enabled(__ibpb_enabled);
}
#endif
#ifdef CONFIG_MAGIC_SYSRQ
......@@ -246,8 +292,6 @@ int sysctl_legacy_va_layout;
u32 sysctl_ibrs_enabled = 0;
EXPORT_SYMBOL(sysctl_ibrs_enabled);
u32 sysctl_ibpb_enabled = 0;
EXPORT_SYMBOL(sysctl_ibpb_enabled);
/* The default sysctl tables: */
......@@ -1245,13 +1289,13 @@ static struct ctl_table kern_table[] = {
.extra2 = &two,
},
{
.procname = "ibpb_enabled",
.data = &sysctl_ibpb_enabled,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_ibpb_ctrl,
.extra1 = &zero,
.extra2 = &one,
.procname = "ibpb_enabled",
.data = &__ibpb_enabled,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = ibpb_enabled_handler,
.extra1 = &zero,
.extra2 = &one,
},
#endif
{ }
......@@ -2437,8 +2481,8 @@ int proc_dointvec_ibrs_ctrl(struct ctl_table *table, int write,
unsigned int cpu;
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);
pr_debug("sysctl_ibrs_enabled = %u\n", sysctl_ibrs_enabled);
pr_debug("before:use_ibrs = %d\n", use_ibrs);
mutex_lock(&spec_ctrl_mutex);
if (sysctl_ibrs_enabled == 0) {
/* always set IBRS off */
......@@ -2464,29 +2508,7 @@ int proc_dointvec_ibrs_ctrl(struct ctl_table *table, int write,
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;
}
int proc_dointvec_ibpb_ctrl(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int ret;
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) {
clear_ibpb_disabled();
if (!ibpb_inuse)
/* 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);
pr_debug("after:use_ibrs = %d\n", use_ibrs);
return ret;
}
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment