|
37 | 37 | #include <linux/cpuset.h>
|
38 | 38 | #include <linux/random.h>
|
39 | 39 | #include <linux/cc_platform.h>
|
| 40 | +#include <linux/parser.h> |
40 | 41 |
|
41 | 42 | #include <trace/events/power.h>
|
42 | 43 | #define CREATE_TRACE_POINTS
|
@@ -3174,28 +3175,135 @@ void __init boot_cpu_hotplug_init(void)
|
3174 | 3175 |
|
3175 | 3176 | #ifdef CONFIG_CPU_MITIGATIONS
|
3176 | 3177 | /*
|
3177 |
| - * These are used for a global "mitigations=" cmdline option for toggling |
3178 |
| - * optional CPU mitigations. |
| 3178 | + * All except the cross-thread attack vector are mitigated by default. |
| 3179 | + * Cross-thread mitigation often requires disabling SMT which is expensive |
| 3180 | + * so cross-thread mitigations are only partially enabled by default. |
| 3181 | + * |
| 3182 | + * Guest-to-Host and Guest-to-Guest vectors are only needed if KVM support is |
| 3183 | + * present. |
| 3184 | + */ |
| 3185 | +static bool attack_vectors[NR_CPU_ATTACK_VECTORS] __ro_after_init = { |
| 3186 | + [CPU_MITIGATE_USER_KERNEL] = true, |
| 3187 | + [CPU_MITIGATE_USER_USER] = true, |
| 3188 | + [CPU_MITIGATE_GUEST_HOST] = IS_ENABLED(CONFIG_KVM), |
| 3189 | + [CPU_MITIGATE_GUEST_GUEST] = IS_ENABLED(CONFIG_KVM), |
| 3190 | +}; |
| 3191 | + |
| 3192 | +bool cpu_attack_vector_mitigated(enum cpu_attack_vectors v) |
| 3193 | +{ |
| 3194 | + if (v < NR_CPU_ATTACK_VECTORS) |
| 3195 | + return attack_vectors[v]; |
| 3196 | + |
| 3197 | + WARN_ONCE(1, "Invalid attack vector %d\n", v); |
| 3198 | + return false; |
| 3199 | +} |
| 3200 | + |
| 3201 | +/* |
| 3202 | + * There are 3 global options, 'off', 'auto', 'auto,nosmt'. These may optionally |
| 3203 | + * be combined with attack-vector disables which follow them. |
| 3204 | + * |
| 3205 | + * Examples: |
| 3206 | + * mitigations=auto,no_user_kernel,no_user_user,no_cross_thread |
| 3207 | + * mitigations=auto,nosmt,no_guest_host,no_guest_guest |
| 3208 | + * |
| 3209 | + * mitigations=off is equivalent to disabling all attack vectors. |
3179 | 3210 | */
|
3180 | 3211 | enum cpu_mitigations {
|
3181 | 3212 | CPU_MITIGATIONS_OFF,
|
3182 | 3213 | CPU_MITIGATIONS_AUTO,
|
3183 | 3214 | CPU_MITIGATIONS_AUTO_NOSMT,
|
3184 | 3215 | };
|
3185 | 3216 |
|
| 3217 | +enum { |
| 3218 | + NO_USER_KERNEL, |
| 3219 | + NO_USER_USER, |
| 3220 | + NO_GUEST_HOST, |
| 3221 | + NO_GUEST_GUEST, |
| 3222 | + NO_CROSS_THREAD, |
| 3223 | + NR_VECTOR_PARAMS, |
| 3224 | +}; |
| 3225 | + |
| 3226 | +enum smt_mitigations smt_mitigations __ro_after_init = SMT_MITIGATIONS_AUTO; |
3186 | 3227 | static enum cpu_mitigations cpu_mitigations __ro_after_init = CPU_MITIGATIONS_AUTO;
|
3187 | 3228 |
|
| 3229 | +static const match_table_t global_mitigations = { |
| 3230 | + { CPU_MITIGATIONS_AUTO_NOSMT, "auto,nosmt"}, |
| 3231 | + { CPU_MITIGATIONS_AUTO, "auto"}, |
| 3232 | + { CPU_MITIGATIONS_OFF, "off"}, |
| 3233 | +}; |
| 3234 | + |
| 3235 | +static const match_table_t vector_mitigations = { |
| 3236 | + { NO_USER_KERNEL, "no_user_kernel"}, |
| 3237 | + { NO_USER_USER, "no_user_user"}, |
| 3238 | + { NO_GUEST_HOST, "no_guest_host"}, |
| 3239 | + { NO_GUEST_GUEST, "no_guest_guest"}, |
| 3240 | + { NO_CROSS_THREAD, "no_cross_thread"}, |
| 3241 | + { NR_VECTOR_PARAMS, NULL}, |
| 3242 | +}; |
| 3243 | + |
| 3244 | +static int __init mitigations_parse_global_opt(char *arg) |
| 3245 | +{ |
| 3246 | + int i; |
| 3247 | + |
| 3248 | + for (i = 0; i < ARRAY_SIZE(global_mitigations); i++) { |
| 3249 | + const char *pattern = global_mitigations[i].pattern; |
| 3250 | + |
| 3251 | + if (!strncmp(arg, pattern, strlen(pattern))) { |
| 3252 | + cpu_mitigations = global_mitigations[i].token; |
| 3253 | + return strlen(pattern); |
| 3254 | + } |
| 3255 | + } |
| 3256 | + |
| 3257 | + return 0; |
| 3258 | +} |
| 3259 | + |
3188 | 3260 | static int __init mitigations_parse_cmdline(char *arg)
|
3189 | 3261 | {
|
3190 |
| - if (!strcmp(arg, "off")) |
3191 |
| - cpu_mitigations = CPU_MITIGATIONS_OFF; |
3192 |
| - else if (!strcmp(arg, "auto")) |
3193 |
| - cpu_mitigations = CPU_MITIGATIONS_AUTO; |
3194 |
| - else if (!strcmp(arg, "auto,nosmt")) |
3195 |
| - cpu_mitigations = CPU_MITIGATIONS_AUTO_NOSMT; |
3196 |
| - else |
3197 |
| - pr_crit("Unsupported mitigations=%s, system may still be vulnerable\n", |
3198 |
| - arg); |
| 3262 | + char *s, *p; |
| 3263 | + int len; |
| 3264 | + |
| 3265 | + len = mitigations_parse_global_opt(arg); |
| 3266 | + |
| 3267 | + if (cpu_mitigations_off()) { |
| 3268 | + memset(attack_vectors, 0, sizeof(attack_vectors)); |
| 3269 | + smt_mitigations = SMT_MITIGATIONS_OFF; |
| 3270 | + } else if (cpu_mitigations_auto_nosmt()) { |
| 3271 | + smt_mitigations = SMT_MITIGATIONS_ON; |
| 3272 | + } |
| 3273 | + |
| 3274 | + p = arg + len; |
| 3275 | + |
| 3276 | + if (!*p) |
| 3277 | + return 0; |
| 3278 | + |
| 3279 | + /* Attack vector controls may come after the ',' */ |
| 3280 | + if (*p++ != ',' || !IS_ENABLED(CONFIG_ARCH_HAS_CPU_ATTACK_VECTORS)) { |
| 3281 | + pr_crit("Unsupported mitigations=%s, system may still be vulnerable\n", arg); |
| 3282 | + return 0; |
| 3283 | + } |
| 3284 | + |
| 3285 | + while ((s = strsep(&p, ",")) != NULL) { |
| 3286 | + switch (match_token(s, vector_mitigations, NULL)) { |
| 3287 | + case NO_USER_KERNEL: |
| 3288 | + attack_vectors[CPU_MITIGATE_USER_KERNEL] = false; |
| 3289 | + break; |
| 3290 | + case NO_USER_USER: |
| 3291 | + attack_vectors[CPU_MITIGATE_USER_USER] = false; |
| 3292 | + break; |
| 3293 | + case NO_GUEST_HOST: |
| 3294 | + attack_vectors[CPU_MITIGATE_GUEST_HOST] = false; |
| 3295 | + break; |
| 3296 | + case NO_GUEST_GUEST: |
| 3297 | + attack_vectors[CPU_MITIGATE_GUEST_GUEST] = false; |
| 3298 | + break; |
| 3299 | + case NO_CROSS_THREAD: |
| 3300 | + smt_mitigations = SMT_MITIGATIONS_OFF; |
| 3301 | + break; |
| 3302 | + default: |
| 3303 | + pr_crit("Unsupported mitigations options %s\n", s); |
| 3304 | + return 0; |
| 3305 | + } |
| 3306 | + } |
3199 | 3307 |
|
3200 | 3308 | return 0;
|
3201 | 3309 | }
|
|
0 commit comments