ACK: [PATCH 1/1][SRU][B][F] KVM: x86: Properly reset MMU context at vCPU RESET/INIT

Thadeu Lima de Souza Cascardo cascardo at canonical.com
Wed Oct 27 18:32:58 UTC 2021


On Wed, Oct 27, 2021 at 02:15:16PM -0300, Heitor Alves de Siqueira wrote:
> From: Sean Christopherson <seanjc at google.com>
> 
> BugLink: https://bugs.launchpad.net/bugs/1948862
> 
> Reset the MMU context at vCPU INIT (and RESET for good measure) if CR0.PG
> was set prior to INIT.  Simply re-initializing the current MMU is not
> sufficient as the current root HPA may not be usable in the new context.
> E.g. if TDP is disabled and INIT arrives while the vCPU is in long mode,
> KVM will fail to switch to the 32-bit pae_root and bomb on the next
> VM-Enter due to running with a 64-bit CR3 in 32-bit mode.
> 
> This bug was papered over in both VMX and SVM, but still managed to rear
> its head in the MMU role on VMX.  Because EFER.LMA=1 requires CR0.PG=1,
> kvm_calc_shadow_mmu_root_page_role() checks for EFER.LMA without first
> checking CR0.PG.  VMX's RESET/INIT flow writes CR0 before EFER, and so
> an INIT with the vCPU in 64-bit mode will cause the hack-a-fix to
> generate the wrong MMU role.
> 
> In VMX, the INIT issue is specific to running without unrestricted guest
> since unrestricted guest is available if and only if EPT is enabled.
> Commit 8668a3c468ed ("KVM: VMX: Reset mmu context when entering real
> mode") resolved the issue by forcing a reset when entering emulated real
> mode.
> 
> In SVM, commit ebae871a509d ("kvm: svm: reset mmu on VCPU reset") forced
> a MMU reset on every INIT to workaround the flaw in common x86.  Note, at
> the time the bug was fixed, the SVM problem was exacerbated by a complete
> lack of a CR4 update.
> 
> The vendor resets will be reverted in future patches, primarily to aid
> bisection in case there are non-INIT flows that rely on the existing VMX
> logic.
> 
> Because CR0.PG is unconditionally cleared on INIT, and because CR0.WP and
> all CR4/EFER paging bits are ignored if CR0.PG=0, simply checking that
> CR0.PG was '1' prior to INIT/RESET is sufficient to detect a required MMU
> context reset.
> 
> Cc: stable at vger.kernel.org
> Signed-off-by: Sean Christopherson <seanjc at google.com>
> Message-Id: <20210622175739.3610207-4-seanjc at google.com>
> Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
> (backported from 0aa1837533e5f4be8cc21bbc06314c23ba2c5447)
> Signed-off-by: Heitor Alves de Siqueira <halves at canonical.com>
> Signed-off-by: Matthew Ruffell <matthew.ruffell at canonical.com>
> ---
>  arch/x86/kvm/x86.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
> 
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 0b6edc63103e..3f6a5630f2c0 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -8109,6 +8109,8 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
>  
>  void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
>  {
> +	unsigned long old_cr0 = kvm_read_cr0(vcpu);
> +
>  	kvm_lapic_reset(vcpu, init_event);
>  
>  	vcpu->arch.hflags = 0;
> @@ -8178,6 +8180,17 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
>  	vcpu->arch.ia32_xss = 0;
>  
>  	kvm_x86_ops->vcpu_reset(vcpu, init_event);
> +
> +	/*
> +	 * Reset the MMU context if paging was enabled prior to INIT (which is
> +	 * implied if CR0.PG=1 as CR0 will be '0' prior to RESET).  Unlike the
> +	 * standard CR0/CR4/EFER modification paths, only CR0.PG needs to be
> +	 * checked because it is unconditionally cleared on INIT and all other
> +	 * paging related bits are ignored if paging is disabled, i.e. CR0.WP,
> +	 * CR4, and EFER changes are all irrelevant if CR0.PG was '0'.
> +	 */
> +	if (old_cr0 & X86_CR0_PG)
> +		kvm_mmu_reset_context(vcpu);
>  }
>  
>  void kvm_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector)
> -- 
> 2.33.1

Makes sense, is upstream and fixes a real issue.

Thanks.

Acked-by: Thadeu Lima de Souza Cascardo <cascardo at canonical.com>



More information about the kernel-team mailing list