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

