| From foo@baz Wed Mar 9 04:10:24 PM CET 2022 |
| From: Josh Poimboeuf <jpoimboe@redhat.com> |
| Date: Fri, 18 Feb 2022 11:49:08 -0800 |
| Subject: x86/speculation: Include unprivileged eBPF status in Spectre v2 mitigation reporting |
| |
| From: Josh Poimboeuf <jpoimboe@redhat.com> |
| |
| commit 44a3918c8245ab10c6c9719dd12e7a8d291980d8 upstream. |
| |
| With unprivileged eBPF enabled, eIBRS (without retpoline) is vulnerable |
| to Spectre v2 BHB-based attacks. |
| |
| When both are enabled, print a warning message and report it in the |
| 'spectre_v2' sysfs vulnerabilities file. |
| |
| Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com> |
| Signed-off-by: Borislav Petkov <bp@suse.de> |
| Reviewed-by: Thomas Gleixner <tglx@linutronix.de> |
| [fllinden@amazon.com: backported to 4.19] |
| Signed-off-by: Frank van der Linden <fllinden@amazon.com> |
| [bwh: Backported to 4.9: adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/x86/kernel/cpu/bugs.c | 35 +++++++++++++++++++++++++++++------ |
| include/linux/bpf.h | 11 +++++++++++ |
| kernel/sysctl.c | 8 ++++++++ |
| 3 files changed, 48 insertions(+), 6 deletions(-) |
| |
| --- a/arch/x86/kernel/cpu/bugs.c |
| +++ b/arch/x86/kernel/cpu/bugs.c |
| @@ -30,6 +30,7 @@ |
| #include <asm/cacheflush.h> |
| #include <asm/intel-family.h> |
| #include <asm/e820.h> |
| +#include <linux/bpf.h> |
| |
| #include "cpu.h" |
| |
| @@ -606,6 +607,16 @@ static inline const char *spectre_v2_mod |
| static inline const char *spectre_v2_module_string(void) { return ""; } |
| #endif |
| |
| +#define SPECTRE_V2_EIBRS_EBPF_MSG "WARNING: Unprivileged eBPF is enabled with eIBRS on, data leaks possible via Spectre v2 BHB attacks!\n" |
| + |
| +#ifdef CONFIG_BPF_SYSCALL |
| +void unpriv_ebpf_notify(int new_state) |
| +{ |
| + if (spectre_v2_enabled == SPECTRE_V2_EIBRS && !new_state) |
| + pr_err(SPECTRE_V2_EIBRS_EBPF_MSG); |
| +} |
| +#endif |
| + |
| static inline bool match_option(const char *arg, int arglen, const char *opt) |
| { |
| int len = strlen(opt); |
| @@ -949,6 +960,9 @@ static void __init spectre_v2_select_mit |
| break; |
| } |
| |
| + if (mode == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled()) |
| + pr_err(SPECTRE_V2_EIBRS_EBPF_MSG); |
| + |
| if (spectre_v2_in_eibrs_mode(mode)) { |
| /* Force it so VMEXIT will restore correctly */ |
| x86_spec_ctrl_base |= SPEC_CTRL_IBRS; |
| @@ -1686,6 +1700,20 @@ static char *ibpb_state(void) |
| return ""; |
| } |
| |
| +static ssize_t spectre_v2_show_state(char *buf) |
| +{ |
| + if (spectre_v2_enabled == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled()) |
| + return sprintf(buf, "Vulnerable: Unprivileged eBPF enabled\n"); |
| + |
| + return sprintf(buf, "%s%s%s%s%s%s\n", |
| + spectre_v2_strings[spectre_v2_enabled], |
| + ibpb_state(), |
| + boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "", |
| + stibp_state(), |
| + boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? ", RSB filling" : "", |
| + spectre_v2_module_string()); |
| +} |
| + |
| static ssize_t srbds_show_state(char *buf) |
| { |
| return sprintf(buf, "%s\n", srbds_strings[srbds_mitigation]); |
| @@ -1708,12 +1736,7 @@ static ssize_t cpu_show_common(struct de |
| return sprintf(buf, "%s\n", spectre_v1_strings[spectre_v1_mitigation]); |
| |
| case X86_BUG_SPECTRE_V2: |
| - return sprintf(buf, "%s%s%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled], |
| - ibpb_state(), |
| - boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "", |
| - stibp_state(), |
| - boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? ", RSB filling" : "", |
| - spectre_v2_module_string()); |
| + return spectre_v2_show_state(buf); |
| |
| case X86_BUG_SPEC_STORE_BYPASS: |
| return sprintf(buf, "%s\n", ssb_strings[ssb_mode]); |
| --- a/include/linux/bpf.h |
| +++ b/include/linux/bpf.h |
| @@ -295,6 +295,11 @@ static inline void bpf_long_memcpy(void |
| |
| /* verify correctness of eBPF program */ |
| int bpf_check(struct bpf_prog **fp, union bpf_attr *attr); |
| + |
| +static inline bool unprivileged_ebpf_enabled(void) |
| +{ |
| + return !sysctl_unprivileged_bpf_disabled; |
| +} |
| #else |
| static inline void bpf_register_prog_type(struct bpf_prog_type_list *tl) |
| { |
| @@ -322,6 +327,12 @@ static inline struct bpf_prog *bpf_prog_ |
| { |
| return ERR_PTR(-EOPNOTSUPP); |
| } |
| + |
| +static inline bool unprivileged_ebpf_enabled(void) |
| +{ |
| + return false; |
| +} |
| + |
| #endif /* CONFIG_BPF_SYSCALL */ |
| |
| /* verifier prototypes for helper functions called from eBPF programs */ |
| --- a/kernel/sysctl.c |
| +++ b/kernel/sysctl.c |
| @@ -222,6 +222,11 @@ static int sysrq_sysctl_handler(struct c |
| #endif |
| |
| #ifdef CONFIG_BPF_SYSCALL |
| + |
| +void __weak unpriv_ebpf_notify(int new_state) |
| +{ |
| +} |
| + |
| static int bpf_unpriv_handler(struct ctl_table *table, int write, |
| void *buffer, size_t *lenp, loff_t *ppos) |
| { |
| @@ -239,6 +244,9 @@ static int bpf_unpriv_handler(struct ctl |
| return -EPERM; |
| *(int *)table->data = unpriv_enable; |
| } |
| + |
| + unpriv_ebpf_notify(unpriv_enable); |
| + |
| return ret; |
| } |
| #endif |