From 81e94fefdbf77df97809d83cc765db506eda47de Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Mon, 29 Jan 2018 13:51:48 -0500 Subject: [PATCH] x86/spec: Add 'lfence_enabled' in sysfs To toggle during runtime whether the lfence fallback should be used. If IBRS is enabled warnings will be returned. OraBug: 27472666 Reviewed-by: John Haxby Signed-off-by: Konrad Rzeszutek Wilk --- arch/x86/include/asm/spec_ctrl.h | 8 +++++ arch/x86/kernel/cpu/spec_ctrl.c | 58 ++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/arch/x86/include/asm/spec_ctrl.h b/arch/x86/include/asm/spec_ctrl.h index 891a569b55cb..ce23ed0fb502 100644 --- a/arch/x86/include/asm/spec_ctrl.h +++ b/arch/x86/include/asm/spec_ctrl.h @@ -262,9 +262,17 @@ static inline void clear_ibrs_disabled(void) set_ibrs_inuse(); } +extern u32 sysctl_lfence_enabled; static inline void set_lfence_disabled(void) { use_ibrs |= SPEC_CTRL_LFENCE_OFF; + sysctl_lfence_enabled = 0; +} + +static inline void clear_lfence_disabled(void) +{ + use_ibrs &= ~SPEC_CTRL_LFENCE_OFF; + sysctl_lfence_enabled = 1; } /* indicate usage of IBPB to control execution speculation */ diff --git a/arch/x86/kernel/cpu/spec_ctrl.c b/arch/x86/kernel/cpu/spec_ctrl.c index e74e500eb45e..c27c31cea4f0 100644 --- a/arch/x86/kernel/cpu/spec_ctrl.c +++ b/arch/x86/kernel/cpu/spec_ctrl.c @@ -15,6 +15,8 @@ */ u32 sysctl_ibrs_enabled = 0, sysctl_ibpb_enabled = 0; +/* By default it is enabled. */ +u32 sysctl_lfence_enabled = 1; EXPORT_SYMBOL(sysctl_ibrs_enabled); EXPORT_SYMBOL(sysctl_ibpb_enabled); @@ -142,12 +144,68 @@ static const struct file_operations fops_ibpb_enabled = { .llseek = default_llseek, }; +static ssize_t lfence_enabled_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + uint32_t dummy = 0; + + if (ibrs_disabled) + return __enabled_read(file, user_buf, count, ppos, &sysctl_lfence_enabled); + + return __enabled_read(file, user_buf, count, ppos, &dummy); +} + +static ssize_t lfence_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; + + /* You have to disable IBRS first. */ + if (ibrs_inuse) { + pr_warn("IBRS is enabled. Ignoring request to change lfence_enabled state."); + return -EINVAL; + } + + 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; + + /* Only 0 and 1 are allowed */ + if (enable > 1) + return -EINVAL; + + mutex_lock(&spec_ctrl_mutex); + + if (!enable) + set_lfence_disabled(); + else + clear_lfence_disabled(); + + mutex_unlock(&spec_ctrl_mutex); + return count; +} + +static const struct file_operations fops_lfence_enabled = { + .read = lfence_enabled_read, + .write = lfence_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); debugfs_create_file("ibpb_enabled", S_IRUSR | S_IWUSR, arch_debugfs_dir, NULL, &fops_ibpb_enabled); + debugfs_create_file("lfence_enabled", S_IRUSR | S_IWUSR, + arch_debugfs_dir, NULL, &fops_lfence_enabled); return 0; } late_initcall(debugfs_spec_ctrl); -- 2.50.1