Re: [PATCH 1/2] KVM: x86: Swap order of CPUID entry "index" vs. "significant flag" checks

From: Jim Mattson
Date: Wed Sep 29 2021 - 18:51:38 EST


On Wed, Sep 29, 2021 at 3:24 PM Sean Christopherson <seanjc@xxxxxxxxxx> wrote:
>
> Check whether a CPUID entry's index is significant before checking for a
> matching index to hack-a-fix an undefined behavior bug due to consuming
> uninitialized data. RESET/INIT emulation uses kvm_cpuid() to retrieve
> CPUID.0x1, which does _not_ have a significant index, and fails to
> initialize the dummy variable that doubles as EBX/ECX/EDX output _and_
> ECX, a.k.a. index, input.
>
> Practically speaking, it's _extremely_ unlikely any compiler will yield
> code that causes problems, as the compiler would need to inline the
> kvm_cpuid() call to detect the uninitialized data, and intentionally hose
> the kernel, e.g. insert ud2, instead of simply ignoring the result of
> the index comparison.
>
> Although the sketchy "dummy" pattern was introduced in SVM by commit
> 66f7b72e1171 ("KVM: x86: Make register state after reset conform to
> specification"), it wasn't actually broken until commit 7ff6c0350315
> ("KVM: x86: Remove stateful CPUID handling") arbitrarily swapped the
> order of operations such that "index" was checked before the significant
> flag.
>
> Avoid consuming uninitialized data by reverting to checking the flag
> before the index purely so that the fix can be easily backported; the
> offending RESET/INIT code has been refactored, moved, and consolidated
> from vendor code to common x86 since the bug was introduced. A future
> patch will directly address the bad RESET/INIT behavior.
>
> The undefined behavior was detected by syzbot + KernelMemorySanitizer.
>
> BUG: KMSAN: uninit-value in cpuid_entry2_find arch/x86/kvm/cpuid.c:68
> BUG: KMSAN: uninit-value in kvm_find_cpuid_entry arch/x86/kvm/cpuid.c:1103
> BUG: KMSAN: uninit-value in kvm_cpuid+0x456/0x28f0 arch/x86/kvm/cpuid.c:1183
> cpuid_entry2_find arch/x86/kvm/cpuid.c:68 [inline]
> kvm_find_cpuid_entry arch/x86/kvm/cpuid.c:1103 [inline]
> kvm_cpuid+0x456/0x28f0 arch/x86/kvm/cpuid.c:1183
> kvm_vcpu_reset+0x13fb/0x1c20 arch/x86/kvm/x86.c:10885
> kvm_apic_accept_events+0x58f/0x8c0 arch/x86/kvm/lapic.c:2923
> vcpu_enter_guest+0xfd2/0x6d80 arch/x86/kvm/x86.c:9534
> vcpu_run+0x7f5/0x18d0 arch/x86/kvm/x86.c:9788
> kvm_arch_vcpu_ioctl_run+0x245b/0x2d10 arch/x86/kvm/x86.c:10020
>
> Local variable ----dummy@kvm_vcpu_reset created at:
> kvm_vcpu_reset+0x1fb/0x1c20 arch/x86/kvm/x86.c:10812
> kvm_apic_accept_events+0x58f/0x8c0 arch/x86/kvm/lapic.c:2923
>
> Reported-by: syzbot+f3985126b746b3d59c9d@xxxxxxxxxxxxxxxxxxxxxxxxx
> Reported-by: Alexander Potapenko <glider@xxxxxxxxxx>
> Fixes: 2a24be79b6b7 ("KVM: VMX: Set EDX at INIT with CPUID.0x1, Family-Model-Stepping")
> Fixes: 7ff6c0350315 ("KVM: x86: Remove stateful CPUID handling")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx>
Reviewed-by: Jim Mattson <jmattson@xxxxxxxxxx>