From 0000000000000000000000000000000000000000 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 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CVE-2017-5753 CVE-2017-5715 Signed-off-by: Tim Chen Signed-off-by: Andy Whitcroft Signed-off-by: Kleber Sacilotto de Souza (cherry picked from commit 85789933bc45a3e763823675bd0d80e3e617f234) Signed-off-by: Fabian Grünbichler --- arch/x86/kernel/cpu/intel.c | 22 ++++++++++++---------- arch/x86/kernel/cpu/microcode/core.c | 2 ++ kernel/smp.c | 4 ++++ kernel/sysctl.c | 14 +++++++++++++- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index c69ea2efbed1..8d558e24783c 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -628,16 +628,18 @@ static void init_intel(struct cpuinfo_x86 *c) init_intel_misc_features(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/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 6450aeda72fc..55086921d29e 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -538,12 +538,14 @@ static ssize_t reload_store(struct device *dev, if (boot_cpu_has(X86_FEATURE_SPEC_CTRL)) { printk_once(KERN_INFO "FEATURE SPEC_CTRL Present\n"); + mutex_lock(&spec_ctrl_mutex); set_ibrs_supported(); set_ibpb_supported(); if (ibrs_inuse) sysctl_ibrs_enabled = 1; if (ibpb_inuse) sysctl_ibpb_enabled = 1; + mutex_unlock(&spec_ctrl_mutex); } mutex_unlock(µcode_mutex); diff --git a/kernel/smp.c b/kernel/smp.c index 3bece045f4a4..a224ec0c540c 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -519,6 +519,10 @@ int use_ibpb; EXPORT_SYMBOL(use_ibpb); #endif +/* 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 69c37bd6251a..47a37792109d 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -69,6 +69,7 @@ #include #include +#include #include #ifdef CONFIG_X86 @@ -2634,12 +2635,17 @@ int proc_dointvec_minmax(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; @@ -2649,6 +2655,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; } @@ -2661,6 +2669,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(); @@ -2684,6 +2693,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; } @@ -2696,6 +2706,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) { @@ -2704,6 +2715,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.14.2