From: David Woodhouse <[email protected]>

The architectural failure mode for an invalid VTL transition is #UD at
the VMCALL, not a hypercall status — a status would advance RIP and
complete the call. Define a result flag for the forwarded-hypercall
completion which queues #UD at the unadvanced RIP and ignores the rest
of the result.

Signed-off-by: David Woodhouse <[email protected]>
Assisted-by: LLM
---
 arch/x86/kvm/hyperv.c          | 14 +++++++++++++-
 include/uapi/linux/kvm.h       |  8 ++++++++
 tools/include/uapi/linux/kvm.h |  9 +++++++++
 3 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
index ec669dafda6e..e41d101e327a 100644
--- a/arch/x86/kvm/hyperv.c
+++ b/arch/x86/kvm/hyperv.c
@@ -2473,7 +2473,19 @@ static int kvm_hv_hypercall_complete(struct kvm_vcpu 
*vcpu, u64 result)
 
 static int kvm_hv_hypercall_complete_userspace(struct kvm_vcpu *vcpu)
 {
-       return kvm_hv_hypercall_complete(vcpu, 
vcpu->run->hyperv.u.hcall.result);
+       u64 result = vcpu->run->hyperv.u.hcall.result;
+
+       /*
+        * A hypercall the VMM judged malformed beyond returning a status
+        * (such as a VTL call that is invalid in the current state) faults
+        * at the instruction instead of completing.
+        */
+       if (result & KVM_HV_HCALL_RESULT_RAISE_UD) {
+               kvm_queue_exception(vcpu, UD_VECTOR);
+               return 1;
+       }
+
+       return kvm_hv_hypercall_complete(vcpu, result);
 }
 
 static int kvm_hvcall_signal_event(struct kvm_vcpu *vcpu, struct kvm_hv_hcall 
*hc)
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 2aeb8c5172cb..b55e28be5181 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1016,6 +1016,14 @@ struct kvm_enable_cap {
 #define KVM_CAP_S390_VSIE_ESAMODE 248
 #define KVM_CAP_PLANES 249
 #define KVM_CAP_HYPERV_FORWARD_HCALL 250
+
+/*
+ * Userspace completion of a forwarded Hyper-V hypercall (KVM_EXIT_HYPERV_HCALL
+ * under KVM_CAP_HYPERV_FORWARD_HCALL): setting this bit in the result makes
+ * KVM raise #UD at the faulting instruction instead of completing the
+ * hypercall; all other result bits are then ignored.
+ */
+#define KVM_HV_HCALL_RESULT_RAISE_UD   (1ULL << 63)
 #define KVM_CAP_HCALL_FAULT_EXIT 252
 
 struct kvm_irq_routing_irqchip {
diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h
index 8d9f7e6bba19..b55e28be5181 100644
--- a/tools/include/uapi/linux/kvm.h
+++ b/tools/include/uapi/linux/kvm.h
@@ -1017,6 +1017,15 @@ struct kvm_enable_cap {
 #define KVM_CAP_PLANES 249
 #define KVM_CAP_HYPERV_FORWARD_HCALL 250
 
+/*
+ * Userspace completion of a forwarded Hyper-V hypercall (KVM_EXIT_HYPERV_HCALL
+ * under KVM_CAP_HYPERV_FORWARD_HCALL): setting this bit in the result makes
+ * KVM raise #UD at the faulting instruction instead of completing the
+ * hypercall; all other result bits are then ignored.
+ */
+#define KVM_HV_HCALL_RESULT_RAISE_UD   (1ULL << 63)
+#define KVM_CAP_HCALL_FAULT_EXIT 252
+
 struct kvm_irq_routing_irqchip {
        __u32 irqchip;
        __u32 pin;
-- 
2.50.1


Reply via email to