| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- From d637e8b6db21d282cfb1fd789ae60807cc87c867 Mon Sep 17 00:00:00 2001
- From: Andi Kleen <[email protected]>
- Date: Fri, 13 Oct 2017 14:56:42 -0700
- Subject: [PATCH 066/242] x86/cpuid: Add generic table for CPUID dependencies
- MIME-Version: 1.0
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- CVE-2017-5754
- Some CPUID features depend on other features. Currently it's
- possible to to clear dependent features, but not clear the base features,
- which can cause various interesting problems.
- This patch implements a generic table to describe dependencies
- between CPUID features, to be used by all code that clears
- CPUID.
- Some subsystems (like XSAVE) had an own implementation of this,
- but it's better to do it all in a single place for everyone.
- Then clear_cpu_cap and setup_clear_cpu_cap always look up
- this table and clear all dependencies too.
- This is intended to be a practical table: only for features
- that make sense to clear. If someone for example clears FPU,
- or other features that are essentially part of the required
- base feature set, not much is going to work. Handling
- that is right now out of scope. We're only handling
- features which can be usefully cleared.
- Signed-off-by: Andi Kleen <[email protected]>
- Reviewed-by: Thomas Gleixner <[email protected]>
- Cc: Jonathan McDowell <[email protected]>
- Cc: Linus Torvalds <[email protected]>
- Cc: Peter Zijlstra <[email protected]>
- Link: http://lkml.kernel.org/r/[email protected]
- Signed-off-by: Ingo Molnar <[email protected]>
- (cherry picked from commit 0b00de857a648dafe7020878c7a27cf776f5edf4)
- Signed-off-by: Andy Whitcroft <[email protected]>
- Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
- (cherry picked from commit 35672522f2fc9a2e116ed1766f190bc08ef5582a)
- Signed-off-by: Fabian Grünbichler <[email protected]>
- ---
- arch/x86/kernel/cpu/Makefile | 1 +
- arch/x86/include/asm/cpufeature.h | 9 ++-
- arch/x86/include/asm/cpufeatures.h | 5 ++
- arch/x86/kernel/cpu/cpuid-deps.c | 113 +++++++++++++++++++++++++++++++++++++
- 4 files changed, 123 insertions(+), 5 deletions(-)
- create mode 100644 arch/x86/kernel/cpu/cpuid-deps.c
- diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
- index e17942c131c8..de260fae1017 100644
- --- a/arch/x86/kernel/cpu/Makefile
- +++ b/arch/x86/kernel/cpu/Makefile
- @@ -22,6 +22,7 @@ obj-y += rdrand.o
- obj-y += match.o
- obj-y += bugs.o
- obj-$(CONFIG_CPU_FREQ) += aperfmperf.o
- +obj-y += cpuid-deps.o
-
- obj-$(CONFIG_PROC_FS) += proc.o
- obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
- diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
- index d59c15c3defd..225fd8374fae 100644
- --- a/arch/x86/include/asm/cpufeature.h
- +++ b/arch/x86/include/asm/cpufeature.h
- @@ -125,11 +125,10 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
- #define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit)
-
- #define set_cpu_cap(c, bit) set_bit(bit, (unsigned long *)((c)->x86_capability))
- -#define clear_cpu_cap(c, bit) clear_bit(bit, (unsigned long *)((c)->x86_capability))
- -#define setup_clear_cpu_cap(bit) do { \
- - clear_cpu_cap(&boot_cpu_data, bit); \
- - set_bit(bit, (unsigned long *)cpu_caps_cleared); \
- -} while (0)
- +
- +extern void setup_clear_cpu_cap(unsigned int bit);
- +extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit);
- +
- #define setup_force_cpu_cap(bit) do { \
- set_cpu_cap(&boot_cpu_data, bit); \
- set_bit(bit, (unsigned long *)cpu_caps_set); \
- diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
- index 5a28e8e55e36..f4e145c4b06f 100644
- --- a/arch/x86/include/asm/cpufeatures.h
- +++ b/arch/x86/include/asm/cpufeatures.h
- @@ -21,6 +21,11 @@
- * this feature bit is not displayed in /proc/cpuinfo at all.
- */
-
- +/*
- + * When adding new features here that depend on other features,
- + * please update the table in kernel/cpu/cpuid-deps.c
- + */
- +
- /* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
- #define X86_FEATURE_FPU ( 0*32+ 0) /* Onboard FPU */
- #define X86_FEATURE_VME ( 0*32+ 1) /* Virtual Mode Extensions */
- diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c
- new file mode 100644
- index 000000000000..e48eb7313120
- --- /dev/null
- +++ b/arch/x86/kernel/cpu/cpuid-deps.c
- @@ -0,0 +1,113 @@
- +/* Declare dependencies between CPUIDs */
- +#include <linux/kernel.h>
- +#include <linux/init.h>
- +#include <linux/module.h>
- +#include <asm/cpufeature.h>
- +
- +struct cpuid_dep {
- + unsigned int feature;
- + unsigned int depends;
- +};
- +
- +/*
- + * Table of CPUID features that depend on others.
- + *
- + * This only includes dependencies that can be usefully disabled, not
- + * features part of the base set (like FPU).
- + *
- + * Note this all is not __init / __initdata because it can be
- + * called from cpu hotplug. It shouldn't do anything in this case,
- + * but it's difficult to tell that to the init reference checker.
- + */
- +const static struct cpuid_dep cpuid_deps[] = {
- + { X86_FEATURE_XSAVEOPT, X86_FEATURE_XSAVE },
- + { X86_FEATURE_XSAVEC, X86_FEATURE_XSAVE },
- + { X86_FEATURE_XSAVES, X86_FEATURE_XSAVE },
- + { X86_FEATURE_AVX, X86_FEATURE_XSAVE },
- + { X86_FEATURE_PKU, X86_FEATURE_XSAVE },
- + { X86_FEATURE_MPX, X86_FEATURE_XSAVE },
- + { X86_FEATURE_XGETBV1, X86_FEATURE_XSAVE },
- + { X86_FEATURE_FXSR_OPT, X86_FEATURE_FXSR },
- + { X86_FEATURE_XMM, X86_FEATURE_FXSR },
- + { X86_FEATURE_XMM2, X86_FEATURE_XMM },
- + { X86_FEATURE_XMM3, X86_FEATURE_XMM2 },
- + { X86_FEATURE_XMM4_1, X86_FEATURE_XMM2 },
- + { X86_FEATURE_XMM4_2, X86_FEATURE_XMM2 },
- + { X86_FEATURE_XMM3, X86_FEATURE_XMM2 },
- + { X86_FEATURE_PCLMULQDQ, X86_FEATURE_XMM2 },
- + { X86_FEATURE_SSSE3, X86_FEATURE_XMM2, },
- + { X86_FEATURE_F16C, X86_FEATURE_XMM2, },
- + { X86_FEATURE_AES, X86_FEATURE_XMM2 },
- + { X86_FEATURE_SHA_NI, X86_FEATURE_XMM2 },
- + { X86_FEATURE_FMA, X86_FEATURE_AVX },
- + { X86_FEATURE_AVX2, X86_FEATURE_AVX, },
- + { X86_FEATURE_AVX512F, X86_FEATURE_AVX, },
- + { X86_FEATURE_AVX512IFMA, X86_FEATURE_AVX512F },
- + { X86_FEATURE_AVX512PF, X86_FEATURE_AVX512F },
- + { X86_FEATURE_AVX512ER, X86_FEATURE_AVX512F },
- + { X86_FEATURE_AVX512CD, X86_FEATURE_AVX512F },
- + { X86_FEATURE_AVX512DQ, X86_FEATURE_AVX512F },
- + { X86_FEATURE_AVX512BW, X86_FEATURE_AVX512F },
- + { X86_FEATURE_AVX512VL, X86_FEATURE_AVX512F },
- + { X86_FEATURE_AVX512VBMI, X86_FEATURE_AVX512F },
- + { X86_FEATURE_AVX512_4VNNIW, X86_FEATURE_AVX512F },
- + { X86_FEATURE_AVX512_4FMAPS, X86_FEATURE_AVX512F },
- + { X86_FEATURE_AVX512_VPOPCNTDQ, X86_FEATURE_AVX512F },
- + {}
- +};
- +
- +static inline void __clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit)
- +{
- + clear_bit32(bit, c->x86_capability);
- +}
- +
- +static inline void __setup_clear_cpu_cap(unsigned int bit)
- +{
- + clear_cpu_cap(&boot_cpu_data, bit);
- + set_bit32(bit, cpu_caps_cleared);
- +}
- +
- +static inline void clear_feature(struct cpuinfo_x86 *c, unsigned int feature)
- +{
- + if (!c)
- + __setup_clear_cpu_cap(feature);
- + else
- + __clear_cpu_cap(c, feature);
- +}
- +
- +static void do_clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature)
- +{
- + bool changed;
- + DECLARE_BITMAP(disable, NCAPINTS * sizeof(u32) * 8);
- + const struct cpuid_dep *d;
- +
- + clear_feature(c, feature);
- +
- + /* Collect all features to disable, handling dependencies */
- + memset(disable, 0, sizeof(disable));
- + __set_bit(feature, disable);
- +
- + /* Loop until we get a stable state. */
- + do {
- + changed = false;
- + for (d = cpuid_deps; d->feature; d++) {
- + if (!test_bit(d->depends, disable))
- + continue;
- + if (__test_and_set_bit(d->feature, disable))
- + continue;
- +
- + changed = true;
- + clear_feature(c, d->feature);
- + }
- + } while (changed);
- +}
- +
- +void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int feature)
- +{
- + do_clear_cpu_cap(c, feature);
- +}
- +
- +void setup_clear_cpu_cap(unsigned int feature)
- +{
- + do_clear_cpu_cap(NULL, feature);
- +}
- --
- 2.14.2
|