| From 9e29c80db7262468251fbaee81e6f4d898e77c8d Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 6 May 2025 07:04:13 +0200 |
| Subject: x86/cpu: Sanitize CPUID(0x80000000) output |
| |
| From: Ahmed S. Darwish <darwi@linutronix.de> |
| |
| [ Upstream commit cc663ba3fe383a628a812f893cc98aafff39ab04 ] |
| |
| 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 |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| arch/x86/kernel/cpu/common.c | 17 +++++++++-------- |
| 1 file changed, 9 insertions(+), 8 deletions(-) |
| |
| diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c |
| index ae9d8aa3ae48e..bd29a436e87e8 100644 |
| --- a/arch/x86/kernel/cpu/common.c |
| +++ b/arch/x86/kernel/cpu/common.c |
| @@ -934,17 +934,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) { |
| -- |
| 2.39.5 |
| |