KVM: load_pdptrs() cleanups
load_pdptrs can be handed an invalid cr3, and it should not oops. This can happen because we injected #gp in set_cr3() after we set vcpu->cr3 to the invalid value, or from kvm_vcpu_ioctl_set_sregs(), or memory configuration changes after the guest did set_cr3(). We should also copy the pdpte array once, before checking and assigning, otherwise an SMP guest can potentially alter the values between the check and the set. Finally one nitpick: ret = 1 should be done as late as possible: this allows GCC to check for unset "ret" should the function change in future. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Avi Kivity <avi@qumranet.com>
This commit is contained in:
parent
3ccb8827fb
commit
c820c2aa27
|
@ -442,30 +442,32 @@ static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
|
||||||
gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
|
gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
|
||||||
unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2;
|
unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2;
|
||||||
int i;
|
int i;
|
||||||
u64 pdpte;
|
|
||||||
u64 *pdpt;
|
u64 *pdpt;
|
||||||
int ret;
|
int ret;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
|
u64 pdpte[ARRAY_SIZE(vcpu->pdptrs)];
|
||||||
|
|
||||||
spin_lock(&vcpu->kvm->lock);
|
spin_lock(&vcpu->kvm->lock);
|
||||||
page = gfn_to_page(vcpu->kvm, pdpt_gfn);
|
page = gfn_to_page(vcpu->kvm, pdpt_gfn);
|
||||||
/* FIXME: !page - emulate? 0xff? */
|
if (!page) {
|
||||||
pdpt = kmap_atomic(page, KM_USER0);
|
ret = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = 1;
|
pdpt = kmap_atomic(page, KM_USER0);
|
||||||
for (i = 0; i < 4; ++i) {
|
memcpy(pdpte, pdpt+offset, sizeof(pdpte));
|
||||||
pdpte = pdpt[offset + i];
|
kunmap_atomic(pdpt, KM_USER0);
|
||||||
if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) {
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(pdpte); ++i) {
|
||||||
|
if ((pdpte[i] & 1) && (pdpte[i] & 0xfffffff0000001e6ull)) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ret = 1;
|
||||||
|
|
||||||
for (i = 0; i < 4; ++i)
|
memcpy(vcpu->pdptrs, pdpte, sizeof(vcpu->pdptrs));
|
||||||
vcpu->pdptrs[i] = pdpt[offset + i];
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kunmap_atomic(pdpt, KM_USER0);
|
|
||||||
spin_unlock(&vcpu->kvm->lock);
|
spin_unlock(&vcpu->kvm->lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
Loading…
Reference in New Issue