]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
x86/cpu: Sanitize CPUID(0x80000000) output
authorAhmed S. Darwish <darwi@linutronix.de>
Tue, 6 May 2025 05:04:13 +0000 (07:04 +0200)
committerIngo Molnar <mingo@kernel.org>
Tue, 6 May 2025 08:04:57 +0000 (10:04 +0200)
CPUID(0x80000000).EAX returns the max extended CPUID leaf available.  On
x86-32 machines without an extended CPUID range, a CPUID(0x80000000)
query will just repeat the output of the last valid standard CPUID leaf
on the CPU; i.e., a garbage values.  Current tip:x86/cpu code protects against
this by doing:

eax = cpuid_eax(0x80000000);
c->extended_cpuid_level = eax;

if ((eax & 0xffff0000) == 0x80000000) {
// CPU has an extended CPUID range. Check for 0x80000001
if (eax >= 0x80000001) {
cpuid(0x80000001, ...);
}
}

This is correct so far.  Afterwards though, the same possibly broken EAX
value is used to check the availability of other extended CPUID leaves:

if (c->extended_cpuid_level >= 0x80000007)
...
if (c->extended_cpuid_level >= 0x80000008)
...
if (c->extended_cpuid_level >= 0x8000000a)
...
if (c->extended_cpuid_level >= 0x8000001f)
...

which is invalid.  Fix this by immediately setting the CPU's max extended
CPUID leaf to zero if CPUID(0x80000000).EAX doesn't indicate a valid
CPUID extended range.

While at it, add a comment, similar to kernel/head_32.S, clarifying the
CPUID(0x80000000) sanity check.

References: 8a50e5135af0 ("x86-32: Use symbolic constants, safer CPUID when enabling EFER.NX")
Fixes: 3da99c977637 ("x86: make (early)_identify_cpu more the same between 32bit and 64 bit")
Signed-off-by: Ahmed S. Darwish <darwi@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: John Ogness <john.ogness@linutronix.de>
Cc: x86-cpuid@lists.linux.dev
Link: https://lore.kernel.org/r/20250506050437.10264-3-darwi@linutronix.de
arch/x86/kernel/cpu/common.c

index 4ada55f126ae9ff2931106e14574cf180f0e197f..e5734df3b4a1ae1c50877f585c35053bee9c0320 100644 (file)
@@ -1005,17 +1005,18 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
                c->x86_capability[CPUID_D_1_EAX] = eax;
        }
 
-       /* AMD-defined flags: level 0x80000001 */
+       /*
+        * Check if extended CPUID leaves are implemented: Max extended
+        * CPUID leaf must be in the 0x80000001-0x8000ffff range.
+        */
        eax = cpuid_eax(0x80000000);
-       c->extended_cpuid_level = eax;
+       c->extended_cpuid_level = ((eax & 0xffff0000) == 0x80000000) ? eax : 0;
 
-       if ((eax & 0xffff0000) == 0x80000000) {
-               if (eax >= 0x80000001) {
-                       cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
+       if (c->extended_cpuid_level >= 0x80000001) {
+               cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
 
-                       c->x86_capability[CPUID_8000_0001_ECX] = ecx;
-                       c->x86_capability[CPUID_8000_0001_EDX] = edx;
-               }
+               c->x86_capability[CPUID_8000_0001_ECX] = ecx;
+               c->x86_capability[CPUID_8000_0001_EDX] = edx;
        }
 
        if (c->extended_cpuid_level >= 0x80000007) {