linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Vitaly Kuznetsov <vkuznets@redhat.com>
To: Sean Christopherson <seanjc@google.com>
Cc: Wanpeng Li <wanpengli@tencent.com>,
	Jim Mattson <jmattson@google.com>, Joerg Roedel <joro@8bytes.org>,
	kvm@vger.kernel.org, linux-hyperv@vger.kernel.org,
	linux-arch@vger.kernel.org, linux-kernel@vger.kernel.org,
	Ajay Garg <ajaygargnsit@gmail.com>,
	Paolo Bonzini <pbonzini@redhat.com>,
	"K. Y. Srinivasan" <kys@microsoft.com>,
	Haiyang Zhang <haiyangz@microsoft.com>,
	Stephen Hemminger <sthemmin@microsoft.com>,
	Wei Liu <wei.liu@kernel.org>, Dexuan Cui <decui@microsoft.com>,
	Arnd Bergmann <arnd@arndb.de>
Subject: Re: [PATCH v2 2/8] KVM: x86: Get the number of Hyper-V sparse banks from the VARHEAD field
Date: Mon, 01 Nov 2021 10:52:07 +0100	[thread overview]
Message-ID: <87a6iokxtk.fsf@vitty.brq.redhat.com> (raw)
In-Reply-To: <20211030000800.3065132-3-seanjc@google.com>

Sean Christopherson <seanjc@google.com> writes:

> Get the number of sparse banks from the VARHEAD field, which the guest is
> required to provide as "The size of a variable header, in QWORDS.", where
> the variable header is:
>
>   Variable Header Bytes = {Total Header Bytes - sizeof(Fixed Header)}
>                           rounded up to nearest multiple of 8
>   Variable HeaderSize = Variable Header Bytes / 8
>
> In other words, the VARHEAD should match the number of sparse banks.
> Keep the manual count as a sanity check, but otherwise rely on the field
> so as to more closely align with the logic defined in the TLFS and to
> allow for future cleanups.
>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
>  arch/x86/kvm/hyperv.c             | 35 ++++++++++++++++++-------------
>  arch/x86/kvm/trace.h              | 14 +++++++------
>  include/asm-generic/hyperv-tlfs.h |  1 +
>  3 files changed, 30 insertions(+), 20 deletions(-)
>
> diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
> index 814d1a1f2cb8..cf18aa1712bf 100644
> --- a/arch/x86/kvm/hyperv.c
> +++ b/arch/x86/kvm/hyperv.c
> @@ -1742,6 +1742,7 @@ struct kvm_hv_hcall {
>  	u64 ingpa;
>  	u64 outgpa;
>  	u16 code;
> +	u16 var_cnt;
>  	u16 rep_cnt;
>  	u16 rep_idx;
>  	bool fast;
> @@ -1761,7 +1762,6 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc, bool
>  	unsigned long *vcpu_mask;
>  	u64 valid_bank_mask;
>  	u64 sparse_banks[64];
> -	int sparse_banks_len;
>  	bool all_cpus;
>  
>  	if (!ex) {
> @@ -1811,24 +1811,28 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc, bool
>  		all_cpus = flush_ex.hv_vp_set.format !=
>  			HV_GENERIC_SET_SPARSE_4K;
>  
> -		sparse_banks_len = bitmap_weight((unsigned long *)&valid_bank_mask, 64);
> +		if (hc->var_cnt != bitmap_weight((unsigned long *)&valid_bank_mask, 64))
> +			return HV_STATUS_INVALID_HYPERCALL_INPUT;

Let's hope Windows doesn't break this ruls when vp_set.format != HV_GENERIC_SET_SPARSE_4K

>  
> -		if (!sparse_banks_len && !all_cpus)
> +		if (!hc->var_cnt && !all_cpus)
>  			goto ret_success;
>  
>  		if (!all_cpus) {
>  			if (hc->fast) {
> -				if (sparse_banks_len > HV_HYPERCALL_MAX_XMM_REGISTERS - 1)
> +				if (hc->var_cnt > HV_HYPERCALL_MAX_XMM_REGISTERS - 1)
>  					return HV_STATUS_INVALID_HYPERCALL_INPUT;
> -				for (i = 0; i < sparse_banks_len; i += 2) {
> +				for (i = 0; i < hc->var_cnt; i += 2) {
>  					sparse_banks[i] = sse128_lo(hc->xmm[i / 2 + 1]);
>  					sparse_banks[i + 1] = sse128_hi(hc->xmm[i / 2 + 1]);
>  				}
>  			} else {
> +				if (hc->var_cnt > 64)
> +					return HV_STATUS_INVALID_HYPERCALL_INPUT;
> +
>  				gpa = hc->ingpa + offsetof(struct hv_tlb_flush_ex,
>  							   hv_vp_set.bank_contents);
>  				if (unlikely(kvm_read_guest(kvm, gpa, sparse_banks,
> -							    sparse_banks_len *
> +							    hc->var_cnt *
>  							    sizeof(sparse_banks[0]))))
>  					return HV_STATUS_INVALID_HYPERCALL_INPUT;
>  			}
> @@ -1884,7 +1888,6 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc, bool
>  	unsigned long *vcpu_mask;
>  	unsigned long valid_bank_mask;
>  	u64 sparse_banks[64];
> -	int sparse_banks_len;
>  	u32 vector;
>  	bool all_cpus;
>  
> @@ -1917,22 +1920,25 @@ static u64 kvm_hv_send_ipi(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc, bool
>  
>  		vector = send_ipi_ex.vector;
>  		valid_bank_mask = send_ipi_ex.vp_set.valid_bank_mask;
> -		sparse_banks_len = bitmap_weight(&valid_bank_mask, 64) *
> -			sizeof(sparse_banks[0]);
> -
>  		all_cpus = send_ipi_ex.vp_set.format == HV_GENERIC_SET_ALL;
>  
> +		if (hc->var_cnt != bitmap_weight(&valid_bank_mask, 64))
> +			return HV_STATUS_INVALID_HYPERCALL_INPUT;
> +
>  		if (all_cpus)
>  			goto check_and_send_ipi;
>  
> -		if (!sparse_banks_len)
> +		if (!hc->var_cnt)
>  			goto ret_success;
>  
> +		if (hc->var_cnt > 64)
> +			return HV_STATUS_INVALID_HYPERCALL_INPUT;
> +
>  		if (kvm_read_guest(kvm,
>  				   hc->ingpa + offsetof(struct hv_send_ipi_ex,
>  							vp_set.bank_contents),
>  				   sparse_banks,
> -				   sparse_banks_len))
> +				   hc->var_cnt * sizeof(sparse_banks[0])))
>  			return HV_STATUS_INVALID_HYPERCALL_INPUT;
>  	}
>  
> @@ -2190,13 +2196,14 @@ int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
>  	}
>  
>  	hc.code = hc.param & 0xffff;
> +	hc.var_cnt = (hc.param & HV_HYPERCALL_VARHEAD_MASK) >> HV_HYPERCALL_VARHEAD_OFFSET;
>  	hc.fast = !!(hc.param & HV_HYPERCALL_FAST_BIT);
>  	hc.rep_cnt = (hc.param >> HV_HYPERCALL_REP_COMP_OFFSET) & 0xfff;
>  	hc.rep_idx = (hc.param >> HV_HYPERCALL_REP_START_OFFSET) & 0xfff;
>  	hc.rep = !!(hc.rep_cnt || hc.rep_idx);
>  
> -	trace_kvm_hv_hypercall(hc.code, hc.fast, hc.rep_cnt, hc.rep_idx,
> -			       hc.ingpa, hc.outgpa);
> +	trace_kvm_hv_hypercall(hc.code, hc.fast, hc.var_cnt, hc.rep_cnt,
> +			       hc.rep_idx, hc.ingpa, hc.outgpa);
>  
>  	if (unlikely(!hv_check_hypercall_access(hv_vcpu, hc.code))) {
>  		ret = HV_STATUS_ACCESS_DENIED;
> diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
> index 953b0fcb21ee..f6625cfb686c 100644
> --- a/arch/x86/kvm/trace.h
> +++ b/arch/x86/kvm/trace.h
> @@ -64,9 +64,9 @@ TRACE_EVENT(kvm_hypercall,
>   * Tracepoint for hypercall.
>   */
>  TRACE_EVENT(kvm_hv_hypercall,
> -	TP_PROTO(__u16 code, bool fast, __u16 rep_cnt, __u16 rep_idx,
> -		 __u64 ingpa, __u64 outgpa),
> -	TP_ARGS(code, fast, rep_cnt, rep_idx, ingpa, outgpa),
> +	TP_PROTO(__u16 code, bool fast,  __u16 var_cnt, __u16 rep_cnt,
> +		 __u16 rep_idx, __u64 ingpa, __u64 outgpa),
> +	TP_ARGS(code, fast, var_cnt, rep_cnt, rep_idx, ingpa, outgpa),
>  
>  	TP_STRUCT__entry(
>  		__field(	__u16,		rep_cnt		)
> @@ -74,6 +74,7 @@ TRACE_EVENT(kvm_hv_hypercall,
>  		__field(	__u64,		ingpa		)
>  		__field(	__u64,		outgpa		)
>  		__field(	__u16, 		code		)
> +		__field(	__u16,		var_cnt		)
>  		__field(	bool,		fast		)
>  	),
>  
> @@ -83,13 +84,14 @@ TRACE_EVENT(kvm_hv_hypercall,
>  		__entry->ingpa		= ingpa;
>  		__entry->outgpa		= outgpa;
>  		__entry->code		= code;
> +		__entry->var_cnt	= var_cnt;
>  		__entry->fast		= fast;
>  	),
>  
> -	TP_printk("code 0x%x %s cnt 0x%x idx 0x%x in 0x%llx out 0x%llx",
> +	TP_printk("code 0x%x %s var_cnt 0x%x cnt 0x%x idx 0x%x in 0x%llx out 0x%llx",

Nit: 'cnt' is (and was) a bit ambiguous, I'd suggest to explicitly say
'rep_cnt' (and probably 'rep_idx') instead.

>  		  __entry->code, __entry->fast ? "fast" : "slow",
> -		  __entry->rep_cnt, __entry->rep_idx,  __entry->ingpa,
> -		  __entry->outgpa)
> +		  __entry->var_cnt, __entry->rep_cnt, __entry->rep_idx,
> +		  __entry->ingpa, __entry->outgpa)
>  );
>  
>  TRACE_EVENT(kvm_hv_hypercall_done,
> diff --git a/include/asm-generic/hyperv-tlfs.h b/include/asm-generic/hyperv-tlfs.h
> index 56348a541c50..1ba8e6da4427 100644
> --- a/include/asm-generic/hyperv-tlfs.h
> +++ b/include/asm-generic/hyperv-tlfs.h
> @@ -182,6 +182,7 @@ enum HV_GENERIC_SET_FORMAT {
>  #define HV_HYPERCALL_RESULT_MASK	GENMASK_ULL(15, 0)
>  #define HV_HYPERCALL_FAST_BIT		BIT(16)
>  #define HV_HYPERCALL_VARHEAD_OFFSET	17
> +#define HV_HYPERCALL_VARHEAD_MASK	GENMASK_ULL(26, 17)
>  #define HV_HYPERCALL_REP_COMP_OFFSET	32
>  #define HV_HYPERCALL_REP_COMP_1		BIT_ULL(32)
>  #define HV_HYPERCALL_REP_COMP_MASK	GENMASK_ULL(43, 32)

Reviewed-by: Vitaly Kuznetsov <vkuznets@redhat.com>

-- 
Vitaly


  reply	other threads:[~2021-11-01  9:54 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-30  0:07 [PATCH v2 0/8] KVM: x86: Hyper-V hypercall fix and cleanups Sean Christopherson
2021-10-30  0:07 ` [PATCH v2 1/8] KVM: x86: Ignore sparse banks size for an "all CPUs", non-sparse IPI req Sean Christopherson
2021-11-01  9:05   ` Vitaly Kuznetsov
2021-10-30  0:07 ` [PATCH v2 2/8] KVM: x86: Get the number of Hyper-V sparse banks from the VARHEAD field Sean Christopherson
2021-11-01  9:52   ` Vitaly Kuznetsov [this message]
2021-10-30  0:07 ` [PATCH v2 3/8] KVM: x86: Refactor kvm_hv_flush_tlb() to reduce indentation Sean Christopherson
2021-11-01 10:00   ` Vitaly Kuznetsov
2021-12-03 23:45     ` Sean Christopherson
2021-10-30  0:07 ` [PATCH v2 4/8] KVM: x86: Add a helper to get the sparse VP_SET for IPIs and TLB flushes Sean Christopherson
2021-11-01 10:06   ` Vitaly Kuznetsov
2021-10-30  0:07 ` [PATCH v2 5/8] KVM: x86: Don't bother reading sparse banks that end up being ignored Sean Christopherson
2021-11-01  9:46   ` Vitaly Kuznetsov
2021-10-30  0:07 ` [PATCH v2 6/8] KVM: x86: Shove vp_bitmap handling down into sparse_set_to_vcpu_mask() Sean Christopherson
2021-11-01 10:12   ` Vitaly Kuznetsov
2021-10-30  0:07 ` [PATCH v2 7/8] KVM: x86: Reject fixeds-size Hyper-V hypercalls with non-zero "var_cnt" Sean Christopherson
2021-11-01 10:27   ` Vitaly Kuznetsov
2021-12-03 23:48     ` Sean Christopherson
2021-10-30  0:08 ` [PATCH v2 8/8] KVM: x86: Add checks for reserved-to-zero Hyper-V hypercall fields Sean Christopherson
2021-11-01 10:33   ` Vitaly Kuznetsov
2021-12-02  2:13     ` Sean Christopherson
2021-12-02 15:16       ` Michael Kelley (LINUX)
2021-12-03 14:09         ` ** POTENTIAL FRAUD ALERT - RED HAT ** " Vitaly Kuznetsov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87a6iokxtk.fsf@vitty.brq.redhat.com \
    --to=vkuznets@redhat.com \
    --cc=ajaygargnsit@gmail.com \
    --cc=arnd@arndb.de \
    --cc=decui@microsoft.com \
    --cc=haiyangz@microsoft.com \
    --cc=jmattson@google.com \
    --cc=joro@8bytes.org \
    --cc=kvm@vger.kernel.org \
    --cc=kys@microsoft.com \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-hyperv@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=seanjc@google.com \
    --cc=sthemmin@microsoft.com \
    --cc=wanpengli@tencent.com \
    --cc=wei.liu@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).