KVM: x86: Reject fixeds-size Hyper-V hypercalls with non-zero "var_cnt"
authorSean Christopherson <seanjc@google.com>
Tue, 7 Dec 2021 22:09:25 +0000 (22:09 +0000)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 10 Feb 2022 18:50:35 +0000 (13:50 -0500)
Reject Hyper-V hypercalls if the guest specifies a non-zero variable size
header (var_cnt in KVM) for a hypercall that has a fixed header size.
Per the TLFS:

  It is illegal to specify a non-zero variable header size for a
  hypercall that is not explicitly documented as accepting variable sized
  input headers. In such a case the hypercall will result in a return
  code of HV_STATUS_INVALID_HYPERCALL_INPUT.

Note, at least some of the various DEBUG commands likely aren't allowed
to use variable size headers, but the TLFS documentation doesn't clearly
state what is/isn't allowed.  Omit them for now to avoid unnecessary
breakage.

Signed-off-by: Sean Christopherson <seanjc@google.com>
Reviewed-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Message-Id: <20211207220926.718794-8-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/hyperv.c

index e46f267585f46073f2462365f82d1f5e60748982..acabe9d898cf99817971f61ff73b0f39e27ff276 100644 (file)
@@ -2253,14 +2253,14 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
 
        switch (hc.code) {
        case HVCALL_NOTIFY_LONG_SPIN_WAIT:
-               if (unlikely(hc.rep)) {
+               if (unlikely(hc.rep || hc.var_cnt)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
                kvm_vcpu_on_spin(vcpu, true);
                break;
        case HVCALL_SIGNAL_EVENT:
-               if (unlikely(hc.rep)) {
+               if (unlikely(hc.rep || hc.var_cnt)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
@@ -2270,7 +2270,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
                fallthrough;    /* maybe userspace knows this conn_id */
        case HVCALL_POST_MESSAGE:
                /* don't bother userspace if it has no way to handle it */
-               if (unlikely(hc.rep || !to_hv_synic(vcpu)->active)) {
+               if (unlikely(hc.rep || hc.var_cnt || !to_hv_synic(vcpu)->active)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
@@ -2283,14 +2283,14 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
                                kvm_hv_hypercall_complete_userspace;
                return 0;
        case HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST:
-               if (unlikely(!hc.rep_cnt || hc.rep_idx)) {
+               if (unlikely(!hc.rep_cnt || hc.rep_idx || hc.var_cnt)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
                ret = kvm_hv_flush_tlb(vcpu, &hc, false);
                break;
        case HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE:
-               if (unlikely(hc.rep)) {
+               if (unlikely(hc.rep || hc.var_cnt)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }
@@ -2311,7 +2311,7 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
                ret = kvm_hv_flush_tlb(vcpu, &hc, true);
                break;
        case HVCALL_SEND_IPI:
-               if (unlikely(hc.rep)) {
+               if (unlikely(hc.rep || hc.var_cnt)) {
                        ret = HV_STATUS_INVALID_HYPERCALL_INPUT;
                        break;
                }