diff options
| author | David S. Miller <davem@davemloft.net> | 2018-01-17 00:00:25 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2018-01-17 00:10:42 -0500 |
| commit | c02b3741eb99a1ec733e6134c53ba59e43e19e97 (patch) | |
| tree | ff7dd96c32dec2abe530e7101378443dabcb8962 /arch/x86/kernel/cpu/bugs.c | |
| parent | 7018d1b3f20fb4308ed9bc577160cb8ffb79b62a (diff) | |
| parent | 8cbab92dff778e516064c13113ca15d4869ec883 (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Overlapping changes all over.
The mini-qdisc bits were a little bit tricky, however.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/x86/kernel/cpu/bugs.c')
| -rw-r--r-- | arch/x86/kernel/cpu/bugs.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index ba0b2424c9b0..e4dc26185aa7 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c | |||
| @@ -10,6 +10,10 @@ | |||
| 10 | */ | 10 | */ |
| 11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
| 12 | #include <linux/utsname.h> | 12 | #include <linux/utsname.h> |
| 13 | #include <linux/cpu.h> | ||
| 14 | |||
| 15 | #include <asm/nospec-branch.h> | ||
| 16 | #include <asm/cmdline.h> | ||
| 13 | #include <asm/bugs.h> | 17 | #include <asm/bugs.h> |
| 14 | #include <asm/processor.h> | 18 | #include <asm/processor.h> |
| 15 | #include <asm/processor-flags.h> | 19 | #include <asm/processor-flags.h> |
| @@ -20,6 +24,8 @@ | |||
| 20 | #include <asm/pgtable.h> | 24 | #include <asm/pgtable.h> |
| 21 | #include <asm/set_memory.h> | 25 | #include <asm/set_memory.h> |
| 22 | 26 | ||
| 27 | static void __init spectre_v2_select_mitigation(void); | ||
| 28 | |||
| 23 | void __init check_bugs(void) | 29 | void __init check_bugs(void) |
| 24 | { | 30 | { |
| 25 | identify_boot_cpu(); | 31 | identify_boot_cpu(); |
| @@ -29,6 +35,9 @@ void __init check_bugs(void) | |||
| 29 | print_cpu_info(&boot_cpu_data); | 35 | print_cpu_info(&boot_cpu_data); |
| 30 | } | 36 | } |
| 31 | 37 | ||
| 38 | /* Select the proper spectre mitigation before patching alternatives */ | ||
| 39 | spectre_v2_select_mitigation(); | ||
| 40 | |||
| 32 | #ifdef CONFIG_X86_32 | 41 | #ifdef CONFIG_X86_32 |
| 33 | /* | 42 | /* |
| 34 | * Check whether we are able to run this kernel safely on SMP. | 43 | * Check whether we are able to run this kernel safely on SMP. |
| @@ -60,3 +69,179 @@ void __init check_bugs(void) | |||
| 60 | set_memory_4k((unsigned long)__va(0), 1); | 69 | set_memory_4k((unsigned long)__va(0), 1); |
| 61 | #endif | 70 | #endif |
| 62 | } | 71 | } |
| 72 | |||
| 73 | /* The kernel command line selection */ | ||
| 74 | enum spectre_v2_mitigation_cmd { | ||
| 75 | SPECTRE_V2_CMD_NONE, | ||
| 76 | SPECTRE_V2_CMD_AUTO, | ||
| 77 | SPECTRE_V2_CMD_FORCE, | ||
| 78 | SPECTRE_V2_CMD_RETPOLINE, | ||
| 79 | SPECTRE_V2_CMD_RETPOLINE_GENERIC, | ||
| 80 | SPECTRE_V2_CMD_RETPOLINE_AMD, | ||
| 81 | }; | ||
| 82 | |||
| 83 | static const char *spectre_v2_strings[] = { | ||
| 84 | [SPECTRE_V2_NONE] = "Vulnerable", | ||
| 85 | [SPECTRE_V2_RETPOLINE_MINIMAL] = "Vulnerable: Minimal generic ASM retpoline", | ||
| 86 | [SPECTRE_V2_RETPOLINE_MINIMAL_AMD] = "Vulnerable: Minimal AMD ASM retpoline", | ||
| 87 | [SPECTRE_V2_RETPOLINE_GENERIC] = "Mitigation: Full generic retpoline", | ||
| 88 | [SPECTRE_V2_RETPOLINE_AMD] = "Mitigation: Full AMD retpoline", | ||
| 89 | }; | ||
| 90 | |||
| 91 | #undef pr_fmt | ||
| 92 | #define pr_fmt(fmt) "Spectre V2 mitigation: " fmt | ||
| 93 | |||
| 94 | static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NONE; | ||
| 95 | |||
| 96 | static void __init spec2_print_if_insecure(const char *reason) | ||
| 97 | { | ||
| 98 | if (boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) | ||
| 99 | pr_info("%s\n", reason); | ||
| 100 | } | ||
| 101 | |||
| 102 | static void __init spec2_print_if_secure(const char *reason) | ||
| 103 | { | ||
| 104 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) | ||
| 105 | pr_info("%s\n", reason); | ||
| 106 | } | ||
| 107 | |||
| 108 | static inline bool retp_compiler(void) | ||
| 109 | { | ||
| 110 | return __is_defined(RETPOLINE); | ||
| 111 | } | ||
| 112 | |||
| 113 | static inline bool match_option(const char *arg, int arglen, const char *opt) | ||
| 114 | { | ||
| 115 | int len = strlen(opt); | ||
| 116 | |||
| 117 | return len == arglen && !strncmp(arg, opt, len); | ||
| 118 | } | ||
| 119 | |||
| 120 | static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) | ||
| 121 | { | ||
| 122 | char arg[20]; | ||
| 123 | int ret; | ||
| 124 | |||
| 125 | ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, | ||
| 126 | sizeof(arg)); | ||
| 127 | if (ret > 0) { | ||
| 128 | if (match_option(arg, ret, "off")) { | ||
| 129 | goto disable; | ||
| 130 | } else if (match_option(arg, ret, "on")) { | ||
| 131 | spec2_print_if_secure("force enabled on command line."); | ||
| 132 | return SPECTRE_V2_CMD_FORCE; | ||
| 133 | } else if (match_option(arg, ret, "retpoline")) { | ||
| 134 | spec2_print_if_insecure("retpoline selected on command line."); | ||
| 135 | return SPECTRE_V2_CMD_RETPOLINE; | ||
| 136 | } else if (match_option(arg, ret, "retpoline,amd")) { | ||
| 137 | if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) { | ||
| 138 | pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n"); | ||
| 139 | return SPECTRE_V2_CMD_AUTO; | ||
| 140 | } | ||
| 141 | spec2_print_if_insecure("AMD retpoline selected on command line."); | ||
| 142 | return SPECTRE_V2_CMD_RETPOLINE_AMD; | ||
| 143 | } else if (match_option(arg, ret, "retpoline,generic")) { | ||
| 144 | spec2_print_if_insecure("generic retpoline selected on command line."); | ||
| 145 | return SPECTRE_V2_CMD_RETPOLINE_GENERIC; | ||
| 146 | } else if (match_option(arg, ret, "auto")) { | ||
| 147 | return SPECTRE_V2_CMD_AUTO; | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | if (!cmdline_find_option_bool(boot_command_line, "nospectre_v2")) | ||
| 152 | return SPECTRE_V2_CMD_AUTO; | ||
| 153 | disable: | ||
| 154 | spec2_print_if_insecure("disabled on command line."); | ||
| 155 | return SPECTRE_V2_CMD_NONE; | ||
| 156 | } | ||
| 157 | |||
| 158 | static void __init spectre_v2_select_mitigation(void) | ||
| 159 | { | ||
| 160 | enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline(); | ||
| 161 | enum spectre_v2_mitigation mode = SPECTRE_V2_NONE; | ||
| 162 | |||
| 163 | /* | ||
| 164 | * If the CPU is not affected and the command line mode is NONE or AUTO | ||
| 165 | * then nothing to do. | ||
| 166 | */ | ||
| 167 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2) && | ||
| 168 | (cmd == SPECTRE_V2_CMD_NONE || cmd == SPECTRE_V2_CMD_AUTO)) | ||
| 169 | return; | ||
| 170 | |||
| 171 | switch (cmd) { | ||
| 172 | case SPECTRE_V2_CMD_NONE: | ||
| 173 | return; | ||
| 174 | |||
| 175 | case SPECTRE_V2_CMD_FORCE: | ||
| 176 | /* FALLTRHU */ | ||
| 177 | case SPECTRE_V2_CMD_AUTO: | ||
| 178 | goto retpoline_auto; | ||
| 179 | |||
| 180 | case SPECTRE_V2_CMD_RETPOLINE_AMD: | ||
| 181 | if (IS_ENABLED(CONFIG_RETPOLINE)) | ||
| 182 | goto retpoline_amd; | ||
| 183 | break; | ||
| 184 | case SPECTRE_V2_CMD_RETPOLINE_GENERIC: | ||
| 185 | if (IS_ENABLED(CONFIG_RETPOLINE)) | ||
| 186 | goto retpoline_generic; | ||
| 187 | break; | ||
| 188 | case SPECTRE_V2_CMD_RETPOLINE: | ||
| 189 | if (IS_ENABLED(CONFIG_RETPOLINE)) | ||
| 190 | goto retpoline_auto; | ||
| 191 | break; | ||
| 192 | } | ||
| 193 | pr_err("kernel not compiled with retpoline; no mitigation available!"); | ||
| 194 | return; | ||
| 195 | |||
| 196 | retpoline_auto: | ||
| 197 | if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { | ||
| 198 | retpoline_amd: | ||
| 199 | if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) { | ||
| 200 | pr_err("LFENCE not serializing. Switching to generic retpoline\n"); | ||
| 201 | goto retpoline_generic; | ||
| 202 | } | ||
| 203 | mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_AMD : | ||
| 204 | SPECTRE_V2_RETPOLINE_MINIMAL_AMD; | ||
| 205 | setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD); | ||
| 206 | setup_force_cpu_cap(X86_FEATURE_RETPOLINE); | ||
| 207 | } else { | ||
| 208 | retpoline_generic: | ||
| 209 | mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_GENERIC : | ||
| 210 | SPECTRE_V2_RETPOLINE_MINIMAL; | ||
| 211 | setup_force_cpu_cap(X86_FEATURE_RETPOLINE); | ||
| 212 | } | ||
| 213 | |||
| 214 | spectre_v2_enabled = mode; | ||
| 215 | pr_info("%s\n", spectre_v2_strings[mode]); | ||
| 216 | } | ||
| 217 | |||
| 218 | #undef pr_fmt | ||
| 219 | |||
| 220 | #ifdef CONFIG_SYSFS | ||
| 221 | ssize_t cpu_show_meltdown(struct device *dev, | ||
| 222 | struct device_attribute *attr, char *buf) | ||
| 223 | { | ||
| 224 | if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN)) | ||
| 225 | return sprintf(buf, "Not affected\n"); | ||
| 226 | if (boot_cpu_has(X86_FEATURE_PTI)) | ||
| 227 | return sprintf(buf, "Mitigation: PTI\n"); | ||
| 228 | return sprintf(buf, "Vulnerable\n"); | ||
| 229 | } | ||
| 230 | |||
| 231 | ssize_t cpu_show_spectre_v1(struct device *dev, | ||
| 232 | struct device_attribute *attr, char *buf) | ||
| 233 | { | ||
| 234 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1)) | ||
| 235 | return sprintf(buf, "Not affected\n"); | ||
| 236 | return sprintf(buf, "Vulnerable\n"); | ||
| 237 | } | ||
| 238 | |||
| 239 | ssize_t cpu_show_spectre_v2(struct device *dev, | ||
| 240 | struct device_attribute *attr, char *buf) | ||
| 241 | { | ||
| 242 | if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) | ||
| 243 | return sprintf(buf, "Not affected\n"); | ||
| 244 | |||
| 245 | return sprintf(buf, "%s\n", spectre_v2_strings[spectre_v2_enabled]); | ||
| 246 | } | ||
| 247 | #endif | ||
