Commit 696ca779 authored by Radim Krčmář's avatar Radim Krčmář

KVM: x86: fix #UD address of failed Hyper-V hypercalls

If the hypercall was called from userspace or real mode, KVM injects #UD
and then advances RIP, so it looks like #UD was caused by the following
instruction.  This probably won't cause more than confusion, but could
give an unexpected access to guest OS' instruction emulator.

Also, refactor the code to count hv hypercalls that were handled by the
virt userspace.

Fixes: 6356ee0c ("x86: Delay skip of emulated hypercall instruction")
Reviewed-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Signed-off-by: default avatarRadim Krčmář <rkrcmar@redhat.com>
parent 1eaafe91
...@@ -1260,14 +1260,18 @@ static void kvm_hv_hypercall_set_result(struct kvm_vcpu *vcpu, u64 result) ...@@ -1260,14 +1260,18 @@ static void kvm_hv_hypercall_set_result(struct kvm_vcpu *vcpu, u64 result)
} }
} }
static int kvm_hv_hypercall_complete_userspace(struct kvm_vcpu *vcpu) static int kvm_hv_hypercall_complete(struct kvm_vcpu *vcpu, u64 result)
{ {
struct kvm_run *run = vcpu->run; kvm_hv_hypercall_set_result(vcpu, result);
++vcpu->stat.hypercalls;
kvm_hv_hypercall_set_result(vcpu, run->hyperv.u.hcall.result);
return kvm_skip_emulated_instruction(vcpu); return kvm_skip_emulated_instruction(vcpu);
} }
static int kvm_hv_hypercall_complete_userspace(struct kvm_vcpu *vcpu)
{
return kvm_hv_hypercall_complete(vcpu, vcpu->run->hyperv.u.hcall.result);
}
static u16 kvm_hvcall_signal_event(struct kvm_vcpu *vcpu, bool fast, u64 param) static u16 kvm_hvcall_signal_event(struct kvm_vcpu *vcpu, bool fast, u64 param)
{ {
struct eventfd_ctx *eventfd; struct eventfd_ctx *eventfd;
...@@ -1350,7 +1354,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) ...@@ -1350,7 +1354,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
/* Hypercall continuation is not supported yet */ /* Hypercall continuation is not supported yet */
if (rep_cnt || rep_idx) { if (rep_cnt || rep_idx) {
ret = HV_STATUS_INVALID_HYPERCALL_CODE; ret = HV_STATUS_INVALID_HYPERCALL_CODE;
goto set_result; goto out;
} }
switch (code) { switch (code) {
...@@ -1381,9 +1385,8 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu) ...@@ -1381,9 +1385,8 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
break; break;
} }
set_result: out:
kvm_hv_hypercall_set_result(vcpu, ret); return kvm_hv_hypercall_complete(vcpu, ret);
return 1;
} }
void kvm_hv_init_vm(struct kvm *kvm) void kvm_hv_init_vm(struct kvm *kvm)
......
...@@ -6676,11 +6676,8 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) ...@@ -6676,11 +6676,8 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
unsigned long nr, a0, a1, a2, a3, ret; unsigned long nr, a0, a1, a2, a3, ret;
int op_64_bit; int op_64_bit;
if (kvm_hv_hypercall_enabled(vcpu->kvm)) { if (kvm_hv_hypercall_enabled(vcpu->kvm))
if (!kvm_hv_hypercall(vcpu)) return kvm_hv_hypercall(vcpu);
return 0;
goto out;
}
nr = kvm_register_read(vcpu, VCPU_REGS_RAX); nr = kvm_register_read(vcpu, VCPU_REGS_RAX);
a0 = kvm_register_read(vcpu, VCPU_REGS_RBX); a0 = kvm_register_read(vcpu, VCPU_REGS_RBX);
...@@ -6701,7 +6698,7 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) ...@@ -6701,7 +6698,7 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
if (kvm_x86_ops->get_cpl(vcpu) != 0) { if (kvm_x86_ops->get_cpl(vcpu) != 0) {
ret = -KVM_EPERM; ret = -KVM_EPERM;
goto out_error; goto out;
} }
switch (nr) { switch (nr) {
...@@ -6721,12 +6718,11 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) ...@@ -6721,12 +6718,11 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
ret = -KVM_ENOSYS; ret = -KVM_ENOSYS;
break; break;
} }
out_error: out:
if (!op_64_bit) if (!op_64_bit)
ret = (u32)ret; ret = (u32)ret;
kvm_register_write(vcpu, VCPU_REGS_RAX, ret); kvm_register_write(vcpu, VCPU_REGS_RAX, ret);
out:
++vcpu->stat.hypercalls; ++vcpu->stat.hypercalls;
return kvm_skip_emulated_instruction(vcpu); return kvm_skip_emulated_instruction(vcpu);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment