linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] KVM: x86: prevent setting unsupported XSAVE states
@ 2013-09-05 12:21 Paolo Bonzini
  2013-09-08  9:54 ` Gleb Natapov
  0 siblings, 1 reply; 4+ messages in thread
From: Paolo Bonzini @ 2013-09-05 12:21 UTC (permalink / raw)
  To: linux-kernel; +Cc: kvm, Gleb Natapov

A guest can still attempt to save and restore XSAVE states even if they
have been masked in CPUID leaf 0Dh.  This usually is not visible to
the guest, but is still wrong: "Any attempt to set a reserved bit (as
determined by the contents of EAX and EDX after executing CPUID with
EAX=0DH, ECX= 0H) in XCR0 for a given processor will result in a #GP
exception".

The patch also performs the same checks as __kvm_set_xcr in KVM_SET_XSAVE.
This catches migration from newer to older kernel/processor before the
guest starts running.

Cc: kvm@vger.kernel.org
Cc: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 arch/x86/kvm/cpuid.c |  2 +-
 arch/x86/kvm/x86.c   | 10 ++++++++--
 arch/x86/kvm/x86.h   |  1 +
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index a20ecb5..d7c465d 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -182,7 +182,7 @@ static bool supported_xcr0_bit(unsigned bit)
 {
 	u64 mask = ((u64)1 << bit);
 
-	return mask & (XSTATE_FP | XSTATE_SSE | XSTATE_YMM) & host_xcr0;
+	return mask & KVM_SUPPORTED_XCR0 & host_xcr0;
 }
 
 #define F(x) bit(X86_FEATURE_##x)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 3625798..801a882 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -586,6 +586,8 @@ int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
 		return 1;
 	if ((xcr0 & XSTATE_YMM) && !(xcr0 & XSTATE_SSE))
 		return 1;
+	if (xcr0 & ~KVM_SUPPORTED_XCR0)
+		return 1;
 	if (xcr0 & ~host_xcr0)
 		return 1;
 	kvm_put_guest_xcr0(vcpu);
@@ -2980,10 +2982,14 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
 	u64 xstate_bv =
 		*(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)];
 
-	if (cpu_has_xsave)
+	if (cpu_has_xsave) {
+		if (xstate_bv & ~KVM_SUPPORTED_XCR0)
+			return -EINVAL;
+		if (xstate_bv & ~host_xcr0)
+			return -EINVAL;
 		memcpy(&vcpu->arch.guest_fpu.state->xsave,
 			guest_xsave->region, xstate_size);
-	else {
+	} else {
 		if (xstate_bv & ~XSTATE_FPSSE)
 			return -EINVAL;
 		memcpy(&vcpu->arch.guest_fpu.state->fxsave,
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index e224f7a..587fb9e 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -122,6 +122,7 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
 	gva_t addr, void *val, unsigned int bytes,
 	struct x86_exception *exception);
 
+#define KVM_SUPPORTED_XCR0	(XSTATE_FP | XSTATE_SSE | XSTATE_YMM)
 extern u64 host_xcr0;
 
 extern struct static_key kvm_no_apic_vcpu;
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] KVM: x86: prevent setting unsupported XSAVE states
  2013-09-05 12:21 [PATCH] KVM: x86: prevent setting unsupported XSAVE states Paolo Bonzini
@ 2013-09-08  9:54 ` Gleb Natapov
  2013-09-09 14:09   ` Paolo Bonzini
  0 siblings, 1 reply; 4+ messages in thread
From: Gleb Natapov @ 2013-09-08  9:54 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: linux-kernel, kvm

On Thu, Sep 05, 2013 at 02:21:54PM +0200, Paolo Bonzini wrote:
> A guest can still attempt to save and restore XSAVE states even if they
> have been masked in CPUID leaf 0Dh.  This usually is not visible to
> the guest, but is still wrong: "Any attempt to set a reserved bit (as
> determined by the contents of EAX and EDX after executing CPUID with
> EAX=0DH, ECX= 0H) in XCR0 for a given processor will result in a #GP
> exception".
> 
> The patch also performs the same checks as __kvm_set_xcr in KVM_SET_XSAVE.
> This catches migration from newer to older kernel/processor before the
> guest starts running.
> 
> Cc: kvm@vger.kernel.org
> Cc: Gleb Natapov <gleb@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  arch/x86/kvm/cpuid.c |  2 +-
>  arch/x86/kvm/x86.c   | 10 ++++++++--
>  arch/x86/kvm/x86.h   |  1 +
>  3 files changed, 10 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> index a20ecb5..d7c465d 100644
> --- a/arch/x86/kvm/cpuid.c
> +++ b/arch/x86/kvm/cpuid.c
> @@ -182,7 +182,7 @@ static bool supported_xcr0_bit(unsigned bit)
>  {
>  	u64 mask = ((u64)1 << bit);
>  
> -	return mask & (XSTATE_FP | XSTATE_SSE | XSTATE_YMM) & host_xcr0;
> +	return mask & KVM_SUPPORTED_XCR0 & host_xcr0;
>  }
>  
>  #define F(x) bit(X86_FEATURE_##x)
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 3625798..801a882 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -586,6 +586,8 @@ int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
>  		return 1;
>  	if ((xcr0 & XSTATE_YMM) && !(xcr0 & XSTATE_SSE))
>  		return 1;
> +	if (xcr0 & ~KVM_SUPPORTED_XCR0)
> +		return 1;
Shouldn't we check guest's cpuid here?

>  	if (xcr0 & ~host_xcr0)
>  		return 1;
>  	kvm_put_guest_xcr0(vcpu);
> @@ -2980,10 +2982,14 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
>  	u64 xstate_bv =
>  		*(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)];
>  
> -	if (cpu_has_xsave)
> +	if (cpu_has_xsave) {
> +		if (xstate_bv & ~KVM_SUPPORTED_XCR0)
> +			return -EINVAL;
> +		if (xstate_bv & ~host_xcr0)
> +			return -EINVAL;
And here?

>  		memcpy(&vcpu->arch.guest_fpu.state->xsave,
>  			guest_xsave->region, xstate_size);
> -	else {
> +	} else {
>  		if (xstate_bv & ~XSTATE_FPSSE)
>  			return -EINVAL;
>  		memcpy(&vcpu->arch.guest_fpu.state->fxsave,
> diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
> index e224f7a..587fb9e 100644
> --- a/arch/x86/kvm/x86.h
> +++ b/arch/x86/kvm/x86.h
> @@ -122,6 +122,7 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
>  	gva_t addr, void *val, unsigned int bytes,
>  	struct x86_exception *exception);
>  
> +#define KVM_SUPPORTED_XCR0	(XSTATE_FP | XSTATE_SSE | XSTATE_YMM)
>  extern u64 host_xcr0;
>  
>  extern struct static_key kvm_no_apic_vcpu;
> -- 
> 1.8.3.1

--
			Gleb.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] KVM: x86: prevent setting unsupported XSAVE states
  2013-09-08  9:54 ` Gleb Natapov
@ 2013-09-09 14:09   ` Paolo Bonzini
  2013-09-09 16:57     ` Gleb Natapov
  0 siblings, 1 reply; 4+ messages in thread
From: Paolo Bonzini @ 2013-09-09 14:09 UTC (permalink / raw)
  To: Gleb Natapov; +Cc: linux-kernel, kvm

Il 08/09/2013 11:54, Gleb Natapov ha scritto:
> On Thu, Sep 05, 2013 at 02:21:54PM +0200, Paolo Bonzini wrote:
>> A guest can still attempt to save and restore XSAVE states even if they
>> have been masked in CPUID leaf 0Dh.  This usually is not visible to
>> the guest, but is still wrong: "Any attempt to set a reserved bit (as
>> determined by the contents of EAX and EDX after executing CPUID with
>> EAX=0DH, ECX= 0H) in XCR0 for a given processor will result in a #GP
>> exception".
>>
>> The patch also performs the same checks as __kvm_set_xcr in KVM_SET_XSAVE.
>> This catches migration from newer to older kernel/processor before the
>> guest starts running.
>>
>> Cc: kvm@vger.kernel.org
>> Cc: Gleb Natapov <gleb@redhat.com>
>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>> ---
>>  arch/x86/kvm/cpuid.c |  2 +-
>>  arch/x86/kvm/x86.c   | 10 ++++++++--
>>  arch/x86/kvm/x86.h   |  1 +
>>  3 files changed, 10 insertions(+), 3 deletions(-)
>>
>> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
>> index a20ecb5..d7c465d 100644
>> --- a/arch/x86/kvm/cpuid.c
>> +++ b/arch/x86/kvm/cpuid.c
>> @@ -182,7 +182,7 @@ static bool supported_xcr0_bit(unsigned bit)
>>  {
>>  	u64 mask = ((u64)1 << bit);
>>  
>> -	return mask & (XSTATE_FP | XSTATE_SSE | XSTATE_YMM) & host_xcr0;
>> +	return mask & KVM_SUPPORTED_XCR0 & host_xcr0;
>>  }
>>  
>>  #define F(x) bit(X86_FEATURE_##x)
>> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
>> index 3625798..801a882 100644
>> --- a/arch/x86/kvm/x86.c
>> +++ b/arch/x86/kvm/x86.c
>> @@ -586,6 +586,8 @@ int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
>>  		return 1;
>>  	if ((xcr0 & XSTATE_YMM) && !(xcr0 & XSTATE_SSE))
>>  		return 1;
>> +	if (xcr0 & ~KVM_SUPPORTED_XCR0)
>> +		return 1;
> Shouldn't we check guest's cpuid here?

Yes.

>>  	if (xcr0 & ~host_xcr0)
>>  		return 1;
>>  	kvm_put_guest_xcr0(vcpu);
>> @@ -2980,10 +2982,14 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
>>  	u64 xstate_bv =
>>  		*(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)];
>>  
>> -	if (cpu_has_xsave)
>> +	if (cpu_has_xsave) {
>> +		if (xstate_bv & ~KVM_SUPPORTED_XCR0)
>> +			return -EINVAL;
>> +		if (xstate_bv & ~host_xcr0)
>> +			return -EINVAL;
> And here?

Here it'd be nice, but we cannot due to backwards compatibility.  We
agreed to change KVM_GET_XSAVE and make it only report states that are
included in CPUID, but we still need to do migration from old kernels
that report all states.

If we change KVM_SET_XSAVE to look at CPUID, and the CPUID does not
include AVX, migration will fail from old kernel (KVM_GET_XSAVE reports
all states) to new kernel (KVM_SET_XSAVES checks against CPUID).

Paolo

>>  		memcpy(&vcpu->arch.guest_fpu.state->xsave,
>>  			guest_xsave->region, xstate_size);
>> -	else {
>> +	} else {
>>  		if (xstate_bv & ~XSTATE_FPSSE)
>>  			return -EINVAL;
>>  		memcpy(&vcpu->arch.guest_fpu.state->fxsave,
>> diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
>> index e224f7a..587fb9e 100644
>> --- a/arch/x86/kvm/x86.h
>> +++ b/arch/x86/kvm/x86.h
>> @@ -122,6 +122,7 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
>>  	gva_t addr, void *val, unsigned int bytes,
>>  	struct x86_exception *exception);
>>  
>> +#define KVM_SUPPORTED_XCR0	(XSTATE_FP | XSTATE_SSE | XSTATE_YMM)
>>  extern u64 host_xcr0;
>>  
>>  extern struct static_key kvm_no_apic_vcpu;
>> -- 
>> 1.8.3.1
> 
> --
> 			Gleb.
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] KVM: x86: prevent setting unsupported XSAVE states
  2013-09-09 14:09   ` Paolo Bonzini
@ 2013-09-09 16:57     ` Gleb Natapov
  0 siblings, 0 replies; 4+ messages in thread
From: Gleb Natapov @ 2013-09-09 16:57 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: linux-kernel, kvm

On Mon, Sep 09, 2013 at 04:09:47PM +0200, Paolo Bonzini wrote:
> Il 08/09/2013 11:54, Gleb Natapov ha scritto:
> > On Thu, Sep 05, 2013 at 02:21:54PM +0200, Paolo Bonzini wrote:
> >> A guest can still attempt to save and restore XSAVE states even if they
> >> have been masked in CPUID leaf 0Dh.  This usually is not visible to
> >> the guest, but is still wrong: "Any attempt to set a reserved bit (as
> >> determined by the contents of EAX and EDX after executing CPUID with
> >> EAX=0DH, ECX= 0H) in XCR0 for a given processor will result in a #GP
> >> exception".
> >>
> >> The patch also performs the same checks as __kvm_set_xcr in KVM_SET_XSAVE.
> >> This catches migration from newer to older kernel/processor before the
> >> guest starts running.
> >>
> >> Cc: kvm@vger.kernel.org
> >> Cc: Gleb Natapov <gleb@redhat.com>
> >> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> >> ---
> >>  arch/x86/kvm/cpuid.c |  2 +-
> >>  arch/x86/kvm/x86.c   | 10 ++++++++--
> >>  arch/x86/kvm/x86.h   |  1 +
> >>  3 files changed, 10 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> >> index a20ecb5..d7c465d 100644
> >> --- a/arch/x86/kvm/cpuid.c
> >> +++ b/arch/x86/kvm/cpuid.c
> >> @@ -182,7 +182,7 @@ static bool supported_xcr0_bit(unsigned bit)
> >>  {
> >>  	u64 mask = ((u64)1 << bit);
> >>  
> >> -	return mask & (XSTATE_FP | XSTATE_SSE | XSTATE_YMM) & host_xcr0;
> >> +	return mask & KVM_SUPPORTED_XCR0 & host_xcr0;
> >>  }
> >>  
> >>  #define F(x) bit(X86_FEATURE_##x)
> >> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> >> index 3625798..801a882 100644
> >> --- a/arch/x86/kvm/x86.c
> >> +++ b/arch/x86/kvm/x86.c
> >> @@ -586,6 +586,8 @@ int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
> >>  		return 1;
> >>  	if ((xcr0 & XSTATE_YMM) && !(xcr0 & XSTATE_SSE))
> >>  		return 1;
> >> +	if (xcr0 & ~KVM_SUPPORTED_XCR0)
> >> +		return 1;
> > Shouldn't we check guest's cpuid here?
> 
> Yes.
> 
> >>  	if (xcr0 & ~host_xcr0)
> >>  		return 1;
> >>  	kvm_put_guest_xcr0(vcpu);
> >> @@ -2980,10 +2982,14 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu,
> >>  	u64 xstate_bv =
> >>  		*(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)];
> >>  
> >> -	if (cpu_has_xsave)
> >> +	if (cpu_has_xsave) {
> >> +		if (xstate_bv & ~KVM_SUPPORTED_XCR0)
> >> +			return -EINVAL;
> >> +		if (xstate_bv & ~host_xcr0)
> >> +			return -EINVAL;
> > And here?
> 
> Here it'd be nice, but we cannot due to backwards compatibility.  We
> agreed to change KVM_GET_XSAVE and make it only report states that are
> included in CPUID, but we still need to do migration from old kernels
> that report all states.
> 
> If we change KVM_SET_XSAVE to look at CPUID, and the CPUID does not
> include AVX, migration will fail from old kernel (KVM_GET_XSAVE reports
> all states) to new kernel (KVM_SET_XSAVES checks against CPUID).
> 
Yeah :(

--
			Gleb.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-09-09 16:58 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-09-05 12:21 [PATCH] KVM: x86: prevent setting unsupported XSAVE states Paolo Bonzini
2013-09-08  9:54 ` Gleb Natapov
2013-09-09 14:09   ` Paolo Bonzini
2013-09-09 16:57     ` Gleb Natapov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).