From: Konrad Rzeszutek Wilk Date: Fri, 5 Jan 2018 03:37:27 +0000 (-0500) Subject: x86/spec_ctrl: Provide the sysfs version of the ibrs_enabled X-Git-Tag: v4.1.12-124.31.3~1296 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=fbd7b4246d27e637593e9ca29021e231c72f7319;p=users%2Fjedix%2Flinux-maple.git x86/spec_ctrl: Provide the sysfs version of the ibrs_enabled as well as the proc version. This is rather important as customers are asking about the sysfs now. But this may change in the future. See https://lkml.org/lkml/2018/1/6/303 Orabug: 27344012 CVE: CVE-2017-5715 Reviewed-by: Todd Vierling Acked-by: John Haxby Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Kirtikar Kashyap --- diff --git a/arch/x86/include/asm/spec_ctrl.h b/arch/x86/include/asm/spec_ctrl.h index d4df538ce72d..5f7e27644a81 100644 --- a/arch/x86/include/asm/spec_ctrl.h +++ b/arch/x86/include/asm/spec_ctrl.h @@ -191,5 +191,14 @@ ALTERNATIVE "", __stringify(__ASM_DISABLE_IBRS_CLOBBER), X86_FEATURE_SPEC_CTRL ALTERNATIVE __stringify(__ASM_STUFF_RSB), "", X86_FEATURE_SMEP .endm +#else +enum { + IBRS_DISABLED, + /* in host kernel, disabled in guest and userland */ + IBRS_ENABLED, + /* in host kernel and host userland, disabled in guest */ + IBRS_ENABLED_USER, + IBRS_MAX = IBRS_ENABLED_USER, +}; #endif /* __ASSEMBLY__ */ #endif /* _ASM_X86_SPEC_CTRL_H */ diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 9bff68798836..3a2f88bb33c1 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -16,6 +16,7 @@ obj-y := intel_cacheinfo.o scattered.o topology.o obj-y += common.o obj-y += rdrand.o obj-y += match.o +obj-y += spec_ctrl.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o diff --git a/arch/x86/kernel/cpu/spec_ctrl.c b/arch/x86/kernel/cpu/spec_ctrl.c new file mode 100644 index 000000000000..dcfc3c547cbf --- /dev/null +++ b/arch/x86/kernel/cpu/spec_ctrl.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * use_ibrs + * bit 0 = indicate if ibrs is currently in use + * bit 1 = indicate if system supports ibrs + * bit 2 = indicate if admin disables ibrs + */ + +static ssize_t __enabled_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos, unsigned int *field) +{ + char buf[32]; + unsigned int len; + + len = sprintf(buf, "%d\n", READ_ONCE(*field)); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ibrs_enabled_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + return __enabled_read(file, user_buf, count, ppos, &sysctl_ibrs_enabled); +} + +static void spec_ctrl_flush_all_cpus(u32 msr_nr, u64 val) +{ + int cpu; + get_online_cpus(); + for_each_online_cpu(cpu) + wrmsrl_on_cpu(cpu, msr_nr, val); + put_online_cpus(); +} + +static ssize_t ibrs_enabled_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + char buf[32]; + ssize_t len; + unsigned int enable; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (kstrtouint(buf, 0, &enable)) + return -EINVAL; + + if (enable > IBRS_MAX) + return -EINVAL; + + mutex_lock(&spec_ctrl_mutex); + + if (enable == IBRS_DISABLED) { + /* disable IBRS usage */ + set_ibrs_disabled(); + if (use_ibrs & SPEC_CTRL_IBRS_SUPPORTED) + spec_ctrl_flush_all_cpus(MSR_IA32_SPEC_CTRL, SPEC_CTRL_FEATURE_DISABLE_IBRS); + } else if (enable == IBRS_ENABLED) { + /* enable IBRS usage in kernel */ + clear_ibrs_disabled(); + if (use_ibrs & SPEC_CTRL_IBRS_SUPPORTED) + set_ibrs_inuse(); + else + /* Platform don't support IBRS */ + enable = IBRS_DISABLED; + } else if (enable == IBRS_ENABLED_USER) { + /* enable IBRS usage in both userspace and kernel */ + clear_ibrs_disabled(); + /* don't change IBRS value once we set it to always on */ + clear_ibrs_inuse(); + if (use_ibrs & SPEC_CTRL_IBRS_SUPPORTED) + spec_ctrl_flush_all_cpus(MSR_IA32_SPEC_CTRL, SPEC_CTRL_FEATURE_ENABLE_IBRS); + else + /* Platform don't support IBRS */ + enable = IBRS_DISABLED; + } + + WRITE_ONCE(sysctl_ibrs_enabled, enable); + + mutex_unlock(&spec_ctrl_mutex); + return count; +} + +static const struct file_operations fops_ibrs_enabled = { + .read = ibrs_enabled_read, + .write = ibrs_enabled_write, + .llseek = default_llseek, +}; + +static int __init debugfs_spec_ctrl(void) +{ + debugfs_create_file("ibrs_enabled", S_IRUSR | S_IWUSR, + arch_debugfs_dir, NULL, &fops_ibrs_enabled); + return 0; +} +late_initcall(debugfs_spec_ctrl);