[v5,03/15] KVM: SVM: Disable SEV/SEV-ES if NPT is disabled
diff mbox series

Message ID 20210422021125.3417167-4-seanjc@google.com
State New, archived
Headers show
Series
  • KVM: SVM: Misc SEV cleanups
Related show

Commit Message

Sean Christopherson April 22, 2021, 2:11 a.m. UTC
Disable SEV and SEV-ES if NPT is disabled.  While the APM doesn't clearly
state that NPT is mandatory, it's alluded to by:

  The guest page tables, managed by the guest, may mark data memory pages
  as either private or shared, thus allowing selected pages to be shared
  outside the guest.

And practically speaking, shadow paging can't work since KVM can't read
the guest's page tables.

Fixes: e9df09428996 ("KVM: SVM: Add sev module_param")
Cc: Brijesh Singh <brijesh.singh@amd.com
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/kvm/svm/svm.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

Comments

Paolo Bonzini April 22, 2021, 7:14 a.m. UTC | #1
On 22/04/21 04:11, Sean Christopherson wrote:
> Disable SEV and SEV-ES if NPT is disabled.  While the APM doesn't clearly
> state that NPT is mandatory, it's alluded to by:
> 
>    The guest page tables, managed by the guest, may mark data memory pages
>    as either private or shared, thus allowing selected pages to be shared
>    outside the guest.
> 
> And practically speaking, shadow paging can't work since KVM can't read
> the guest's page tables.
> 
> Fixes: e9df09428996 ("KVM: SVM: Add sev module_param")
> Cc: Brijesh Singh <brijesh.singh@amd.com
> Cc: Tom Lendacky <thomas.lendacky@amd.com>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
>   arch/x86/kvm/svm/svm.c | 30 +++++++++++++++---------------
>   1 file changed, 15 insertions(+), 15 deletions(-)
> 
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index fed153314aef..0e8489908216 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -970,7 +970,21 @@ static __init int svm_hardware_setup(void)
>   		kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE);
>   	}
>   
> -	if (IS_ENABLED(CONFIG_KVM_AMD_SEV) && sev) {
> +	/*
> +	 * KVM's MMU doesn't support using 2-level paging for itself, and thus
> +	 * NPT isn't supported if the host is using 2-level paging since host
> +	 * CR4 is unchanged on VMRUN.
> +	 */
> +	if (!IS_ENABLED(CONFIG_X86_64) && !IS_ENABLED(CONFIG_X86_PAE))
> +		npt_enabled = false;

Unrelated, but since you're moving this code: should we be pre-scient 
and tackle host 5-level paging as well?

Support for 5-level page tables on NPT is not hard to fix and could be 
tested by patching QEMU.  However, the !NPT case would also have to be 
fixed by extending the PDP and PML4 stacking trick to a PML5.

However, without real hardware to test on I'd be a bit wary to do it. 
Looking at 5-level EPT there might be other issues (e.g. what's the 
guest MAXPHYADDR) and I would prefer to see what AMD comes up with 
exactly in the APM.  So I would just block loading KVM on hypothetical 
AMD hosts with CR4.LA57=1.

Paolo

> +	if (!boot_cpu_has(X86_FEATURE_NPT))
> +		npt_enabled = false;
> +
> +	kvm_configure_mmu(npt_enabled, get_max_npt_level(), PG_LEVEL_1G);
> +	pr_info("kvm: Nested Paging %sabled\n", npt_enabled ? "en" : "dis");
> +
> +	if (IS_ENABLED(CONFIG_KVM_AMD_SEV) && sev && npt_enabled) {
>   		sev_hardware_setup();
>   	} else {
>   		sev = false;
> @@ -985,20 +999,6 @@ static __init int svm_hardware_setup(void)
>   			goto err;
>   	}
>   
> -	/*
> -	 * KVM's MMU doesn't support using 2-level paging for itself, and thus
> -	 * NPT isn't supported if the host is using 2-level paging since host
> -	 * CR4 is unchanged on VMRUN.
> -	 */
> -	if (!IS_ENABLED(CONFIG_X86_64) && !IS_ENABLED(CONFIG_X86_PAE))
> -		npt_enabled = false;
> -
> -	if (!boot_cpu_has(X86_FEATURE_NPT))
> -		npt_enabled = false;
> -
> -	kvm_configure_mmu(npt_enabled, get_max_npt_level(), PG_LEVEL_1G);
> -	pr_info("kvm: Nested Paging %sabled\n", npt_enabled ? "en" : "dis");
> -
>   	if (nrips) {
>   		if (!boot_cpu_has(X86_FEATURE_NRIPS))
>   			nrips = false;
>
Sean Christopherson April 22, 2021, 4:15 p.m. UTC | #2
On Thu, Apr 22, 2021, Paolo Bonzini wrote:
> On 22/04/21 04:11, Sean Christopherson wrote:
> > Disable SEV and SEV-ES if NPT is disabled.  While the APM doesn't clearly
> > state that NPT is mandatory, it's alluded to by:
> > 
> >    The guest page tables, managed by the guest, may mark data memory pages
> >    as either private or shared, thus allowing selected pages to be shared
> >    outside the guest.
> > 
> > And practically speaking, shadow paging can't work since KVM can't read
> > the guest's page tables.
> > 
> > Fixes: e9df09428996 ("KVM: SVM: Add sev module_param")
> > Cc: Brijesh Singh <brijesh.singh@amd.com
> > Cc: Tom Lendacky <thomas.lendacky@amd.com>
> > Signed-off-by: Sean Christopherson <seanjc@google.com>
> > ---
> >   arch/x86/kvm/svm/svm.c | 30 +++++++++++++++---------------
> >   1 file changed, 15 insertions(+), 15 deletions(-)
> > 
> > diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> > index fed153314aef..0e8489908216 100644
> > --- a/arch/x86/kvm/svm/svm.c
> > +++ b/arch/x86/kvm/svm/svm.c
> > @@ -970,7 +970,21 @@ static __init int svm_hardware_setup(void)
> >   		kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE);
> >   	}
> > -	if (IS_ENABLED(CONFIG_KVM_AMD_SEV) && sev) {
> > +	/*
> > +	 * KVM's MMU doesn't support using 2-level paging for itself, and thus
> > +	 * NPT isn't supported if the host is using 2-level paging since host
> > +	 * CR4 is unchanged on VMRUN.
> > +	 */
> > +	if (!IS_ENABLED(CONFIG_X86_64) && !IS_ENABLED(CONFIG_X86_PAE))
> > +		npt_enabled = false;
> 
> Unrelated, but since you're moving this code: should we be pre-scient and
> tackle host 5-level paging as well?
> 
> Support for 5-level page tables on NPT is not hard to fix and could be
> tested by patching QEMU.  However, the !NPT case would also have to be fixed
> by extending the PDP and PML4 stacking trick to a PML5.

Isn't that backwards?  It's the nested NPT case that requires the stacking trick.
When !NPT is disabled in L0 KVM, 32-bit guests are run with PAE paging.  Maybe
I'm misunderstanding what you're suggesting.
 
> However, without real hardware to test on I'd be a bit wary to do it.
> Looking at 5-level EPT there might be other issues (e.g. what's the guest
> MAXPHYADDR) and I would prefer to see what AMD comes up with exactly in the
> APM.  So I would just block loading KVM on hypothetical AMD hosts with
> CR4.LA57=1.

Agreed, I think blocking KVM makes the most sense.
Paolo Bonzini April 22, 2021, 5:08 p.m. UTC | #3
On 22/04/21 18:15, Sean Christopherson wrote:
>> Support for 5-level page tables on NPT is not hard to fix and could be
>> tested by patching QEMU.  However, the !NPT case would also have to be fixed
>> by extending the PDP and PML4 stacking trick to a PML5.
>   
> Isn't that backwards?  It's the nested NPT case that requires the stacking trick.
> When !NPT is disabled in L0 KVM, 32-bit guests are run with PAE paging.  Maybe
> I'm misunderstanding what you're suggesting.

Yes, you're right.  NPT is easy but we would have to guess what the spec 
would say about MAXPHYADDR, while nNPT would require the stacking of a 
PML5.  Either way, blocking KVM is the easiest thing todo.

Paolo
Sean Christopherson April 22, 2021, 6:11 p.m. UTC | #4
On Thu, Apr 22, 2021, Paolo Bonzini wrote:
> On 22/04/21 18:15, Sean Christopherson wrote:
> > > Support for 5-level page tables on NPT is not hard to fix and could be
> > > tested by patching QEMU.  However, the !NPT case would also have to be fixed
> > > by extending the PDP and PML4 stacking trick to a PML5.
> > Isn't that backwards?  It's the nested NPT case that requires the stacking trick.
> > When !NPT is disabled in L0 KVM, 32-bit guests are run with PAE paging.  Maybe
> > I'm misunderstanding what you're suggesting.
> 
> Yes, you're right.  NPT is easy but we would have to guess what the spec
> would say about MAXPHYADDR, while nNPT would require the stacking of a PML5.
> Either way, blocking KVM is the easiest thing todo.

How about I fold that into the s/lm_root/pml4_root rename[*]?  I.e. make the
blocking of PML5 a functional change, and the rename an opportunistic change?

[*] https://lkml.kernel.org/r/20210318201131.3242619-1-seanjc@google.com
Paolo Bonzini April 23, 2021, 7:08 a.m. UTC | #5
On 22/04/21 20:11, Sean Christopherson wrote:
>> Yes, you're right.  NPT is easy but we would have to guess what the spec
>> would say about MAXPHYADDR, while nNPT would require the stacking of a PML5.
>> Either way, blocking KVM is the easiest thing todo.
> How about I fold that into the s/lm_root/pml4_root rename[*]?  I.e. make the
> blocking of PML5 a functional change, and the rename an opportunistic change?
> 
> [*]https://lkml.kernel.org/r/20210318201131.3242619-1-seanjc@google.com
> 

Yes, that's a good plan.  Thanks,

Paolo

Patch
diff mbox series

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index fed153314aef..0e8489908216 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -970,7 +970,21 @@  static __init int svm_hardware_setup(void)
 		kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE);
 	}
 
-	if (IS_ENABLED(CONFIG_KVM_AMD_SEV) && sev) {
+	/*
+	 * KVM's MMU doesn't support using 2-level paging for itself, and thus
+	 * NPT isn't supported if the host is using 2-level paging since host
+	 * CR4 is unchanged on VMRUN.
+	 */
+	if (!IS_ENABLED(CONFIG_X86_64) && !IS_ENABLED(CONFIG_X86_PAE))
+		npt_enabled = false;
+
+	if (!boot_cpu_has(X86_FEATURE_NPT))
+		npt_enabled = false;
+
+	kvm_configure_mmu(npt_enabled, get_max_npt_level(), PG_LEVEL_1G);
+	pr_info("kvm: Nested Paging %sabled\n", npt_enabled ? "en" : "dis");
+
+	if (IS_ENABLED(CONFIG_KVM_AMD_SEV) && sev && npt_enabled) {
 		sev_hardware_setup();
 	} else {
 		sev = false;
@@ -985,20 +999,6 @@  static __init int svm_hardware_setup(void)
 			goto err;
 	}
 
-	/*
-	 * KVM's MMU doesn't support using 2-level paging for itself, and thus
-	 * NPT isn't supported if the host is using 2-level paging since host
-	 * CR4 is unchanged on VMRUN.
-	 */
-	if (!IS_ENABLED(CONFIG_X86_64) && !IS_ENABLED(CONFIG_X86_PAE))
-		npt_enabled = false;
-
-	if (!boot_cpu_has(X86_FEATURE_NPT))
-		npt_enabled = false;
-
-	kvm_configure_mmu(npt_enabled, get_max_npt_level(), PG_LEVEL_1G);
-	pr_info("kvm: Nested Paging %sabled\n", npt_enabled ? "en" : "dis");
-
 	if (nrips) {
 		if (!boot_cpu_has(X86_FEATURE_NRIPS))
 			nrips = false;