diff mbox

KVM: x86: Fix page-tables reserved bits

Message ID 1396582264-9864-1-git-send-email-namit@cs.technion.ac.il (mailing list archive)
State New, archived
Headers show

Commit Message

Nadav Amit April 4, 2014, 3:31 a.m. UTC
KVM does not handle the reserved bits of x86 page tables correctly:
In PAE, bits 5:8 are reserved in the PDPTE.
In IA-32e, bit 8 is not reserved.

Signed-off-by: Nadav Amit <namit@cs.technion.ac.il>
---
 arch/x86/kvm/mmu.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

Comments

Marcelo Tosatti April 16, 2014, 7:03 p.m. UTC | #1
On Fri, Apr 04, 2014 at 06:31:04AM +0300, Nadav Amit wrote:
> KVM does not handle the reserved bits of x86 page tables correctly:
> In PAE, bits 5:8 are reserved in the PDPTE.
> In IA-32e, bit 8 is not reserved.
> 
> Signed-off-by: Nadav Amit <namit@cs.technion.ac.il>
> ---
>  arch/x86/kvm/mmu.c |    6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
> index f5704d9..3993976 100644
> --- a/arch/x86/kvm/mmu.c
> +++ b/arch/x86/kvm/mmu.c
> @@ -3538,7 +3538,7 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
>  	case PT32E_ROOT_LEVEL:
>  		context->rsvd_bits_mask[0][2] =
>  			rsvd_bits(maxphyaddr, 63) |
> -			rsvd_bits(7, 8) | rsvd_bits(1, 2);	/* PDPTE */
> +			rsvd_bits(5, 8) | rsvd_bits(1, 2);	/* PDPTE */
>  		context->rsvd_bits_mask[0][1] = exb_bit_rsvd |
>  			rsvd_bits(maxphyaddr, 62);	/* PDE */
>  		context->rsvd_bits_mask[0][0] = exb_bit_rsvd |
> @@ -3550,9 +3550,9 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
>  		break;
>  	case PT64_ROOT_LEVEL:
>  		context->rsvd_bits_mask[0][3] = exb_bit_rsvd |
> -			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8);
> +			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 7);
>  		context->rsvd_bits_mask[0][2] = exb_bit_rsvd |
> -			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8);
> +			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 7);

Bit 7 is not reserved either, for the PDPTE (its PageSize bit).

--
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
H. Peter Anvin April 16, 2014, 9:17 p.m. UTC | #2
On 04/16/2014 12:03 PM, Marcelo Tosatti wrote:
>> @@ -3550,9 +3550,9 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
>>  		break;
>>  	case PT64_ROOT_LEVEL:
>>  		context->rsvd_bits_mask[0][3] = exb_bit_rsvd |
>> -			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8);
>> +			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 7);
>>  		context->rsvd_bits_mask[0][2] = exb_bit_rsvd |
>> -			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8);
>> +			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 7);
> 
> Bit 7 is not reserved either, for the PDPTE (its PageSize bit).
> 

In long mode (IA-32e), bit 7 is definitely reserved.

	-hpa

--
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
Marcelo Tosatti April 16, 2014, 10:04 p.m. UTC | #3
On Wed, Apr 16, 2014 at 02:17:08PM -0700, H. Peter Anvin wrote:
> On 04/16/2014 12:03 PM, Marcelo Tosatti wrote:
> >> @@ -3550,9 +3550,9 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
> >>  		break;
> >>  	case PT64_ROOT_LEVEL:
> >>  		context->rsvd_bits_mask[0][3] = exb_bit_rsvd |
> >> -			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8);
> >> +			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 7);
> >>  		context->rsvd_bits_mask[0][2] = exb_bit_rsvd |
> >> -			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8);
> >> +			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 7);
> > 
> > Bit 7 is not reserved either, for the PDPTE (its PageSize bit).
> > 
> 
> In long mode (IA-32e), bit 7 is definitely reserved.
> 
> 	-hpa

There is a separate reserved mask for PS=1, nevermind.

--
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
Paolo Bonzini April 28, 2014, 10:41 a.m. UTC | #4
Il 17/04/2014 00:04, Marcelo Tosatti ha scritto:
>>>> > >> @@ -3550,9 +3550,9 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
>>>> > >>  		break;
>>>> > >>  	case PT64_ROOT_LEVEL:
>>>> > >>  		context->rsvd_bits_mask[0][3] = exb_bit_rsvd |
>>>> > >> -			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8);
>>>> > >> +			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 7);
>>>> > >>  		context->rsvd_bits_mask[0][2] = exb_bit_rsvd |
>>>> > >> -			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8);
>>>> > >> +			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 7);
>>> > >
>>> > > Bit 7 is not reserved either, for the PDPTE (its PageSize bit).
>>> > >
>> >
>> > In long mode (IA-32e), bit 7 is definitely reserved.

It's always reserved for PML4E (rsvd_bits_mask[x][3]), while for PDPTEs 
it is not reserved if you have 1GB pages.

> There is a separate reserved mask for PS=1, nevermind.
>

Yeah, but the situation for IA32e rsvd_bits_mask[0][2] is exactly the 
same as for PAE rsvd_bits_mask[0][1], and we're not marking the bit as 
reserved there.

The right thing to do is to add rsvd_bits(7, 7) to both 
rsvd_bits_mask[0][2] and rsvd_bits_mask[1][2], if 1GB pages are not 
supported.

As written, the patch has no effect on PDPTEs because 
rsvd_bits_mask[0][2] is only accessed if bit 7 is zero.

Nadav, would you mind preparing a follow-up?  Also, how did you find 
these issues and test the fixes?

Paolo
--
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
Nadav Amit April 28, 2014, 12:20 p.m. UTC | #5
On Apr 28, 2014, at 1:41 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:

> Il 17/04/2014 00:04, Marcelo Tosatti ha scritto:
>>>>> > >> @@ -3550,9 +3550,9 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
>>>>> > >>  		break;
>>>>> > >>  	case PT64_ROOT_LEVEL:
>>>>> > >>  		context->rsvd_bits_mask[0][3] = exb_bit_rsvd |
>>>>> > >> -			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8);
>>>>> > >> +			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 7);
>>>>> > >>  		context->rsvd_bits_mask[0][2] = exb_bit_rsvd |
>>>>> > >> -			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8);
>>>>> > >> +			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 7);
>>>> > >
>>>> > > Bit 7 is not reserved either, for the PDPTE (its PageSize bit).
>>>> > >
>>> >
>>> > In long mode (IA-32e), bit 7 is definitely reserved.
> 
> It's always reserved for PML4E (rsvd_bits_mask[x][3]), while for PDPTEs it is not reserved if you have 1GB pages.
> 
>> There is a separate reserved mask for PS=1, nevermind.
>> 
> 
> Yeah, but the situation for IA32e rsvd_bits_mask[0][2] is exactly the same as for PAE rsvd_bits_mask[0][1], and we're not marking the bit as reserved there.
> 
> The right thing to do is to add rsvd_bits(7, 7) to both rsvd_bits_mask[0][2] and rsvd_bits_mask[1][2], if 1GB pages are not supported.
> 
> As written, the patch has no effect on PDPTEs because rsvd_bits_mask[0][2] is only accessed if bit 7 is zero.
> 
> Nadav, would you mind preparing a follow-up?  Also, how did you find these issues and test the fixes?
I will create a follow-up as soon as possible. We encountered the issues in a custom testing environment.
The fixes were validated using the failing tests, but they cover additional cases which might not have been tested.

Regards,
Nadav--
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
diff mbox

Patch

diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index f5704d9..3993976 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -3538,7 +3538,7 @@  static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
 	case PT32E_ROOT_LEVEL:
 		context->rsvd_bits_mask[0][2] =
 			rsvd_bits(maxphyaddr, 63) |
-			rsvd_bits(7, 8) | rsvd_bits(1, 2);	/* PDPTE */
+			rsvd_bits(5, 8) | rsvd_bits(1, 2);	/* PDPTE */
 		context->rsvd_bits_mask[0][1] = exb_bit_rsvd |
 			rsvd_bits(maxphyaddr, 62);	/* PDE */
 		context->rsvd_bits_mask[0][0] = exb_bit_rsvd |
@@ -3550,9 +3550,9 @@  static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
 		break;
 	case PT64_ROOT_LEVEL:
 		context->rsvd_bits_mask[0][3] = exb_bit_rsvd |
-			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8);
+			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 7);
 		context->rsvd_bits_mask[0][2] = exb_bit_rsvd |
-			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 8);
+			rsvd_bits(maxphyaddr, 51) | rsvd_bits(7, 7);
 		context->rsvd_bits_mask[0][1] = exb_bit_rsvd |
 			rsvd_bits(maxphyaddr, 51);
 		context->rsvd_bits_mask[0][0] = exb_bit_rsvd |