diff mbox

KVM: x86: check for cr3 validity in ioctl_set_sregs

Message ID 20090416113044.GA11200@amt.cnet (mailing list archive)
State New, archived
Headers show

Commit Message

Marcelo Tosatti April 16, 2009, 11:30 a.m. UTC
Matt T. Yourst notes that kvm_arch_vcpu_ioctl_set_sregs lacks validity
checking for the new cr3 value:
      
"Userspace callers of KVM_SET_SREGS can pass a bogus value of cr3 to
the kernel. This will trigger a NULL pointer access in gfn_to_rmap()
when userspace next tries to call KVM_RUN on the affected VCPU and kvm
attempts to activate the new non-existent page table root.

This happens since kvm only validates that cr3 points to a valid guest
physical memory page when code *inside* the guest sets cr3. However, kvm
currently trusts the userspace caller (e.g. QEMU) on the host machine to
always supply a valid page table root, rather than properly validating
it along with the rest of the reloaded guest state."

http://sourceforge.net/tracker/?func=detail&atid=893831&aid=2687641&group_id=180599

Check for a valid cr3 address in kvm_arch_vcpu_ioctl_set_sregs, triple
fault in case of failure.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>


--
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

Comments

Avi Kivity April 16, 2009, 12:42 p.m. UTC | #1
Marcelo Tosatti wrote:
> Matt T. Yourst notes that kvm_arch_vcpu_ioctl_set_sregs lacks validity
> checking for the new cr3 value:
>       
> "Userspace callers of KVM_SET_SREGS can pass a bogus value of cr3 to
> the kernel. This will trigger a NULL pointer access in gfn_to_rmap()
> when userspace next tries to call KVM_RUN on the affected VCPU and kvm
> attempts to activate the new non-existent page table root.
>
> This happens since kvm only validates that cr3 points to a valid guest
> physical memory page when code *inside* the guest sets cr3. However, kvm
> currently trusts the userspace caller (e.g. QEMU) on the host machine to
> always supply a valid page table root, rather than properly validating
> it along with the rest of the reloaded guest state."
>
> http://sourceforge.net/tracker/?func=detail&atid=893831&aid=2687641&group_id=180599
>
> Check for a valid cr3 address in kvm_arch_vcpu_ioctl_set_sregs, triple
> fault in case of failure.
>
> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
>
> Index: kvm/arch/x86/kvm/x86.c
> ===================================================================
> --- kvm.orig/arch/x86/kvm/x86.c
> +++ kvm/arch/x86/kvm/x86.c
> @@ -3986,7 +3986,13 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct
>  
>  	vcpu->arch.cr2 = sregs->cr2;
>  	mmu_reset_needed |= vcpu->arch.cr3 != sregs->cr3;
> -	vcpu->arch.cr3 = sregs->cr3;
> +
> +	down_read(&vcpu->kvm->slots_lock);
> +	if (gfn_to_memslot(vcpu->kvm, sregs->cr3 >> PAGE_SHIFT))
> +		vcpu->arch.cr3 = sregs->cr3;
> +	else
> +		set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
> +	up_read(&vcpu->kvm->slots_lock);
>  
>  	kvm_set_cr8(vcpu, sregs->cr8);
>  
>   

Isn't this self-defeating?  If you drop slots_lock, cr3 may be invalid 
again by the time you set cvpu->arch.cr3?
Avi Kivity April 16, 2009, 12:49 p.m. UTC | #2
Avi Kivity wrote:
> Marcelo Tosatti wrote:
>> Matt T. Yourst notes that kvm_arch_vcpu_ioctl_set_sregs lacks validity
>> checking for the new cr3 value:
>>       "Userspace callers of KVM_SET_SREGS can pass a bogus value of 
>> cr3 to
>> the kernel. This will trigger a NULL pointer access in gfn_to_rmap()
>> when userspace next tries to call KVM_RUN on the affected VCPU and kvm
>> attempts to activate the new non-existent page table root.
>>
>> This happens since kvm only validates that cr3 points to a valid guest
>> physical memory page when code *inside* the guest sets cr3. However, kvm
>> currently trusts the userspace caller (e.g. QEMU) on the host machine to
>> always supply a valid page table root, rather than properly validating
>> it along with the rest of the reloaded guest state."
>>
>> http://sourceforge.net/tracker/?func=detail&atid=893831&aid=2687641&group_id=180599 
>>
>>
>> Check for a valid cr3 address in kvm_arch_vcpu_ioctl_set_sregs, triple
>> fault in case of failure.
>>
>> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
>>
>> Index: kvm/arch/x86/kvm/x86.c
>> ===================================================================
>> --- kvm.orig/arch/x86/kvm/x86.c
>> +++ kvm/arch/x86/kvm/x86.c
>> @@ -3986,7 +3986,13 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct
>>  
>>      vcpu->arch.cr2 = sregs->cr2;
>>      mmu_reset_needed |= vcpu->arch.cr3 != sregs->cr3;
>> -    vcpu->arch.cr3 = sregs->cr3;
>> +
>> +    down_read(&vcpu->kvm->slots_lock);
>> +    if (gfn_to_memslot(vcpu->kvm, sregs->cr3 >> PAGE_SHIFT))
>> +        vcpu->arch.cr3 = sregs->cr3;
>> +    else
>> +        set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
>> +    up_read(&vcpu->kvm->slots_lock);
>>  
>>      kvm_set_cr8(vcpu, sregs->cr8);
>>  
>>   
>
> Isn't this self-defeating?  If you drop slots_lock, cr3 may be invalid 
> again by the time you set cvpu->arch.cr3?
>

Uh, sorry, of course not.  I misread down as up.  Bad day for me.  Will 
apply the patch.

Still, don't we have a problem if userspace drops the memory slot where 
cr3 points to?
diff mbox

Patch

Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -3986,7 +3986,13 @@  int kvm_arch_vcpu_ioctl_set_sregs(struct
 
 	vcpu->arch.cr2 = sregs->cr2;
 	mmu_reset_needed |= vcpu->arch.cr3 != sregs->cr3;
-	vcpu->arch.cr3 = sregs->cr3;
+
+	down_read(&vcpu->kvm->slots_lock);
+	if (gfn_to_memslot(vcpu->kvm, sregs->cr3 >> PAGE_SHIFT))
+		vcpu->arch.cr3 = sregs->cr3;
+	else
+		set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
+	up_read(&vcpu->kvm->slots_lock);
 
 	kvm_set_cr8(vcpu, sregs->cr8);