]>
Commit | Line | Data |
---|---|---|
a4b1a797 FG |
1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
2 | From: Andi Kleen <ak@linux.intel.com> | |
3 | Date: Thu, 25 Jan 2018 15:50:28 -0800 | |
4 | Subject: [PATCH] module/retpoline: Warn about missing retpoline in module | |
5 | MIME-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | There's a risk that a kernel which has full retpoline mitigations becomes | |
10 | vulnerable when a module gets loaded that hasn't been compiled with the | |
11 | right compiler or the right option. | |
12 | ||
13 | To enable detection of that mismatch at module load time, add a module info | |
14 | string "retpoline" at build time when the module was compiled with | |
15 | retpoline support. This only covers compiled C source, but assembler source | |
16 | or prebuilt object files are not checked. | |
17 | ||
18 | If a retpoline enabled kernel detects a non retpoline protected module at | |
19 | load time, print a warning and report it in the sysfs vulnerability file. | |
20 | ||
21 | [ tglx: Massaged changelog ] | |
22 | ||
23 | Signed-off-by: Andi Kleen <ak@linux.intel.com> | |
24 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
25 | Cc: David Woodhouse <dwmw2@infradead.org> | |
26 | Cc: gregkh@linuxfoundation.org | |
27 | Cc: torvalds@linux-foundation.org | |
28 | Cc: jeyu@kernel.org | |
29 | Cc: arjan@linux.intel.com | |
30 | Link: https://lkml.kernel.org/r/20180125235028.31211-1-andi@firstfloor.org | |
31 | (backported from commit caf7501a1b4ec964190f31f9c3f163de252273b8) | |
32 | Conflicts: | |
33 | arch/x86/kernel/cpu/bugs.c | |
34 | context changes | |
35 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
36 | --- | |
a4b1a797 | 37 | arch/x86/kernel/cpu/bugs.c | 19 +++++++++++++++++-- |
4cae8e32 | 38 | include/linux/module.h | 9 +++++++++ |
a4b1a797 FG |
39 | kernel/module.c | 11 +++++++++++ |
40 | scripts/mod/modpost.c | 9 +++++++++ | |
41 | 4 files changed, 46 insertions(+), 2 deletions(-) | |
42 | ||
a4b1a797 FG |
43 | diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c |
44 | index d5bafcdb4891..e623bd731a74 100644 | |
45 | --- a/arch/x86/kernel/cpu/bugs.c | |
46 | +++ b/arch/x86/kernel/cpu/bugs.c | |
47 | @@ -11,6 +11,7 @@ | |
48 | #include <linux/utsname.h> | |
49 | #include <linux/cpu.h> | |
50 | #include <linux/smp.h> | |
51 | +#include <linux/module.h> | |
52 | ||
53 | #include <asm/nospec-branch.h> | |
54 | #include <asm/cmdline.h> | |
55 | @@ -93,6 +94,19 @@ static const char *spectre_v2_strings[] = { | |
56 | #define pr_fmt(fmt) "Spectre V2 mitigation: " fmt | |
57 | ||
58 | static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE; | |
59 | +static bool spectre_v2_bad_module; | |
60 | + | |
61 | +#ifdef RETPOLINE | |
62 | +bool retpoline_module_ok(bool has_retpoline) | |
63 | +{ | |
64 | + if (spectre_v2_enabled == SPECTRE_V2_NONE || has_retpoline) | |
65 | + return true; | |
66 | + | |
67 | + pr_err("System may be vunerable to spectre v2\n"); | |
68 | + spectre_v2_bad_module = true; | |
69 | + return false; | |
70 | +} | |
71 | +#endif | |
72 | ||
73 | static void __init spec2_print_if_insecure(const char *reason) | |
74 | { | |
75 | @@ -299,7 +313,8 @@ ssize_t cpu_show_spectre_v2(struct device *dev, | |
76 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) | |
77 | return sprintf(buf, "Not affected\n"); | |
78 | ||
79 | - return sprintf(buf, "%s%s\n", spectre_v2_strings[spectre_v2_enabled], | |
80 | - ibpb_inuse ? ", IBPB (Intel v4)" : ""); | |
81 | + return sprintf(buf, "%s%s%s\n", spectre_v2_strings[spectre_v2_enabled], | |
82 | + ibpb_inuse ? ", IBPB (Intel v4)" : "", | |
83 | + spectre_v2_bad_module ? " - vulnerable module loaded" : ""); | |
84 | } | |
85 | #endif | |
4cae8e32 TL |
86 | diff --git a/include/linux/module.h b/include/linux/module.h |
87 | index e7bdd549e527..c4fdf7661f82 100644 | |
88 | --- a/include/linux/module.h | |
89 | +++ b/include/linux/module.h | |
90 | @@ -794,6 +794,15 @@ static inline void module_bug_finalize(const Elf_Ehdr *hdr, | |
91 | static inline void module_bug_cleanup(struct module *mod) {} | |
92 | #endif /* CONFIG_GENERIC_BUG */ | |
93 | ||
94 | +#ifdef RETPOLINE | |
95 | +extern bool retpoline_module_ok(bool has_retpoline); | |
96 | +#else | |
97 | +static inline bool retpoline_module_ok(bool has_retpoline) | |
98 | +{ | |
99 | + return true; | |
100 | +} | |
101 | +#endif | |
102 | + | |
103 | #ifdef CONFIG_MODULE_SIG | |
104 | static inline bool module_sig_ok(struct module *module) | |
105 | { | |
a4b1a797 FG |
106 | diff --git a/kernel/module.c b/kernel/module.c |
107 | index e5b878b26906..de7db074f793 100644 | |
108 | --- a/kernel/module.c | |
109 | +++ b/kernel/module.c | |
110 | @@ -2855,6 +2855,15 @@ static int check_modinfo_livepatch(struct module *mod, struct load_info *info) | |
111 | } | |
112 | #endif /* CONFIG_LIVEPATCH */ | |
113 | ||
114 | +static void check_modinfo_retpoline(struct module *mod, struct load_info *info) | |
115 | +{ | |
116 | + if (retpoline_module_ok(get_modinfo(info, "retpoline"))) | |
117 | + return; | |
118 | + | |
119 | + pr_warn("%s: loading module not compiled with retpoline compiler.\n", | |
120 | + mod->name); | |
121 | +} | |
122 | + | |
123 | /* Sets info->hdr and info->len. */ | |
124 | static int copy_module_from_user(const void __user *umod, unsigned long len, | |
125 | struct load_info *info) | |
126 | @@ -3021,6 +3030,8 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags) | |
127 | add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK); | |
128 | } | |
129 | ||
130 | + check_modinfo_retpoline(mod, info); | |
131 | + | |
132 | if (get_modinfo(info, "staging")) { | |
133 | add_taint_module(mod, TAINT_CRAP, LOCKDEP_STILL_OK); | |
134 | pr_warn("%s: module is from the staging directory, the quality " | |
135 | diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c | |
136 | index 48397feb08fb..cc91f81ac33e 100644 | |
137 | --- a/scripts/mod/modpost.c | |
138 | +++ b/scripts/mod/modpost.c | |
139 | @@ -2147,6 +2147,14 @@ static void add_intree_flag(struct buffer *b, int is_intree) | |
140 | buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); | |
141 | } | |
142 | ||
143 | +/* Cannot check for assembler */ | |
144 | +static void add_retpoline(struct buffer *b) | |
145 | +{ | |
146 | + buf_printf(b, "\n#ifdef RETPOLINE\n"); | |
147 | + buf_printf(b, "MODULE_INFO(retpoline, \"Y\");\n"); | |
148 | + buf_printf(b, "#endif\n"); | |
149 | +} | |
150 | + | |
151 | static void add_staging_flag(struct buffer *b, const char *name) | |
152 | { | |
153 | static const char *staging_dir = "drivers/staging"; | |
154 | @@ -2492,6 +2500,7 @@ int main(int argc, char **argv) | |
155 | ||
156 | add_header(&buf, mod); | |
157 | add_intree_flag(&buf, !external_module); | |
158 | + add_retpoline(&buf); | |
159 | add_staging_flag(&buf, mod->name); | |
160 | err |= add_versions(&buf, mod); | |
161 | add_depends(&buf, mod, modules); | |
162 | -- | |
163 | 2.14.2 | |
164 |