There's a risk that a kernel that has full retpoline mitigations
becomes vulnerable when a module gets loaded that hasn't been
compiled with the right compiler or the right option.
We cannot fix it, but should at least warn the user when that
happens.
Add a flag to each module if it has been compiled with RETPOLINE
When the a module hasn't been compiled with a retpoline
aware compiler, print a warning and set a taint flag.
For modules it is checked at compile time, however it cannot
check assembler or other non compiled objects used in the module link.
Due to lack of better letter it uses taint option 'Z'
We only set the taint flag for incorrectly compiled modules
now, not for the main kernel, which already has other
report mechanisms.
Also make sure to report vulnerable for spectre if such a module
has been loaded.
v2: Change warning message
v3: Port to latest tree
Cc: jeyu@kernel.org
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
(cherry picked from commit
abc01f3c4bbd927f5e47cc6dff99a76a393d1bbe)
Orabug:
27477743
CVE: CVE-2017-5715
Signed-off-by: Daniel Jordan <daniel.m.jordan@oracle.com>
Conflicts:
Documentation/oops-tracing.txt
(dmj: patch had Documentation/admin-guide/tainted-kernels.rst)
arch/x86/kernel/cpu/bugs_64.c
(dmj: patch had arch/x86/kernel/cpu/bugs.c)
include/linux/kernel.h
kernel/module.c
kernel/panic.c
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Reviewed-by: Pavel Tatashin <pasha.tatashin@oracle.com>
16: 'K' if the kernel has been live patched.
+ 17: 'Z' if a module hasn't been compiled with
+ a retpoline aware compiler and may be vulnerable to data leaks.
+
The primary reason for the 'Tainted: ' string is to tell kernel
debuggers if this is a clean kernel or if anything unusual has
occurred. Tainting is permanent: even if an offending module is
void stop_this_cpu(void *dummy);
void df_debug(struct pt_regs *regs, long error_code);
+
+void disable_retpoline(void);
+bool retpoline_enabled(void);
+
#endif /* _ASM_X86_PROCESSOR_H */
static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE;
+/* A module has been loaded. Disable reporting that we're good. */
+void disable_retpoline(void)
+{
+ spectre_v2_enabled = SPECTRE_V2_NONE;
+ pr_err("system may be vulnerable to spectre\n");
+}
+
+bool retpoline_enabled(void)
+{
+ return spectre_v2_enabled != SPECTRE_V2_NONE;
+}
+
static void __init spec2_print_if_insecure(const char *reason)
{
if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2))
#define TAINT_UNSIGNED_MODULE 13
#define TAINT_SOFTLOCKUP 14
#define TAINT_LIVEPATCH 15
+#define TAINT_NO_RETPOLINE 16
extern const char hex_asc[];
#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
if (!get_modinfo(info, "intree"))
add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK);
-
+#ifdef RETPOLINE
+ if (retpoline_enabled() && !get_modinfo(info, "retpoline")) {
+ if (!test_taint(TAINT_NO_RETPOLINE)) {
+ pr_warn("%s: loading module not compiled with retpoline compiler.\n",
+ mod->name);
+ }
+ add_taint_module(mod, TAINT_NO_RETPOLINE, LOCKDEP_STILL_OK);
+ disable_retpoline();
+ }
+#endif
if (get_modinfo(info, "staging")) {
add_taint_module(mod, TAINT_CRAP, LOCKDEP_STILL_OK);
pr_warn("%s: module is from the staging directory, the quality "
{ TAINT_UNSIGNED_MODULE, 'E', ' ' },
{ TAINT_SOFTLOCKUP, 'L', ' ' },
{ TAINT_LIVEPATCH, 'K', ' ' },
+ { TAINT_NO_RETPOLINE, 'Z', ' ' },
};
/**
* 'E' - Unsigned module has been loaded.
* 'L' - A soft lockup has previously occurred.
* 'K' - Kernel has been live patched.
+ * 'Z' - Module with no retpoline has been loaded
*
* The string is overwritten by the next call to print_tainted().
*/
buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
}
+/* Cannot check for assembler */
+static void add_retpoline(struct buffer *b)
+{
+ buf_printf(b, "\n#ifdef RETPOLINE\n");
+ buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n");
+ buf_printf(b, "#endif\n");
+}
+
static void add_staging_flag(struct buffer *b, const char *name)
{
static const char *staging_dir = "drivers/staging";
add_header(&buf, mod);
add_intree_flag(&buf, !external_module);
+ add_retpoline(&buf);
add_staging_flag(&buf, mod->name);
err |= add_versions(&buf, mod);
add_depends(&buf, mod, modules);