]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
retpoline/module: Taint kernel for missing retpoline in module
authorAndi Kleen <ak@linux.intel.com>
Thu, 4 Jan 2018 14:37:08 +0000 (14:37 +0000)
committerJack Vogel <jack.vogel@oracle.com>
Thu, 8 Feb 2018 18:14:57 +0000 (10:14 -0800)
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>
Documentation/oops-tracing.txt
arch/x86/include/asm/processor.h
arch/x86/kernel/cpu/bugs_64.c
include/linux/kernel.h
kernel/module.c
kernel/panic.c
scripts/mod/modpost.c

index f3ac05cc23e4abb0ea13277fc8a45873351e7ce3..ed510bafa33e06acd7e70dceab74130750f952ea 100644 (file)
@@ -272,6 +272,9 @@ characters, each representing a particular tainted value.
 
  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
index 3154597bfb17aeb7ba187dd957ad384e3efb4563..540dd04d58f82eda7e0294bf899e3148d79a74f0 100644 (file)
@@ -979,4 +979,8 @@ bool xen_set_default_idle(void);
 
 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 */
index d1e84a93f70aa90f6e2d8d7c48a78c1820061971..71934459267788431ee5dedd4ba7c29c51feffd6 100644 (file)
@@ -112,6 +112,18 @@ static const char *spectre_v2_strings[] = {
 
 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))
index 624c1ae8292851737de7665a45f90f6fa7fda5d5..991c600eaf60c2180b9358e1bba04b048a055a7f 100644 (file)
@@ -494,6 +494,7 @@ extern enum system_states {
 #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)]
index c85dd07e0871ad0d0a1ec141338f5057170b3412..634ecdbcb9ad25ee2d60fee7f5e37d3e8ea896eb 100644 (file)
@@ -2713,7 +2713,16 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
 
        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 "
index 21cf87a71e181b42f6e881174168a5a436b6e986..e9999af5307831bca47199abe8e70a05a7102ce3 100644 (file)
@@ -279,6 +279,7 @@ static const struct tnt tnts[] = {
        { TAINT_UNSIGNED_MODULE,        'E', ' ' },
        { TAINT_SOFTLOCKUP,             'L', ' ' },
        { TAINT_LIVEPATCH,              'K', ' ' },
+       { TAINT_NO_RETPOLINE,           'Z', ' ' },
 };
 
 /**
@@ -300,6 +301,7 @@ static const struct tnt tnts[] = {
  *  '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().
  */
index b4b9ba8b6e7552eee8b7f5728c6fb1d286367601..a767c895aa6cc3611ee621815526bee0e0418c45 100644 (file)
@@ -2139,6 +2139,14 @@ static void add_intree_flag(struct buffer *b, int is_intree)
                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";
@@ -2471,6 +2479,7 @@ int main(int argc, char **argv)
 
                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);