linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] KVM: Clean up guest/host cache read/write code
@ 2020-01-09 23:56 Sean Christopherson
  2020-01-09 23:56 ` [PATCH 1/3] KVM: Check for a bad hva before dropping into the ghc slow path Sean Christopherson
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Sean Christopherson @ 2020-01-09 23:56 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: kvm, linux-kernel, Jim Mattson, Andrew Honig, Barret Rhoden

Minor cleanup to fix the underlying crustiness that led to an uninitialized
variable warning reported by Barret.

The first two patches are tagged with Fixes:, but I don't know that they're
actually worth backporting to stable.  Functionally, everthing works, it's
just a bit weird and AFAICT not what is intended.  It might be preferable
to take Barret's patch[*] first and only mark that for stable, as it fixes
the immediate issue without revamping __kvm_gfn_to_hva_cache_init().

[*] https://lkml.kernel.org/r/20200109195855.17353-1-brho@google.com

Sean Christopherson (3):
  KVM: Check for a bad hva before dropping into the ghc slow path
  KVM: Clean up __kvm_gfn_to_hva_cache_init() and its callers
  KVM: Return immediately if __kvm_gfn_to_hva_cache_init() fails

 virt/kvm/kvm_main.c | 45 ++++++++++++++++++++++++++-------------------
 1 file changed, 26 insertions(+), 19 deletions(-)

-- 
2.24.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/3] KVM: Check for a bad hva before dropping into the ghc slow path
  2020-01-09 23:56 [PATCH 0/3] KVM: Clean up guest/host cache read/write code Sean Christopherson
@ 2020-01-09 23:56 ` Sean Christopherson
  2020-01-09 23:56 ` [PATCH 2/3] KVM: Clean up __kvm_gfn_to_hva_cache_init() and its callers Sean Christopherson
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Sean Christopherson @ 2020-01-09 23:56 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: kvm, linux-kernel, Jim Mattson, Andrew Honig, Barret Rhoden

When reading/writing using the guest/host cache, check for a bad hva
before checking for a NULL memslot, which triggers the slow path for
handing cross-page accesses.  Because the memslot is nullified on error
by __kvm_gfn_to_hva_cache_init(), if the bad hva is encountered after
crossing into a new page, then the kvm_{read,write}_guest() slow path
could potentially write/access the first chunk prior to detecting the
bad hva.

Arguably, performing a partial access is semantically correct from an
architectural perspective, but that behavior is certainly not intended.
In the original implementation, memslot was not explicitly nullified
and therefore the partial access behavior varied based on whether the
memslot itself was null, or if the hva was simply bad.  The current
behavior was introduced as a seemingly unintentional side effect in
commit f1b9dd5eb86c ("kvm: Disallow wraparound in
kvm_gfn_to_hva_cache_init"), which justified the change with "since some
callers don't check the return code from this function, it sit seems
prudent to clear ghc->memslot in the event of an error".

Regardless of intent, the partial access is dependent on _not_ checking
the result of the cache initialization, which is arguably a bug in its
own right, at best simply weird.

Fixes: 8f964525a121 ("KVM: Allow cross page reads and writes from cached translations.")
Cc: Jim Mattson <jmattson@google.com>
Cc: Andrew Honig <ahonig@google.com>
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
 virt/kvm/kvm_main.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 3aa21bec028d..c02c073b9d43 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2205,12 +2205,12 @@ int kvm_write_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
 	if (slots->generation != ghc->generation)
 		__kvm_gfn_to_hva_cache_init(slots, ghc, ghc->gpa, ghc->len);
 
+	if (kvm_is_error_hva(ghc->hva))
+		return -EFAULT;
+
 	if (unlikely(!ghc->memslot))
 		return kvm_write_guest(kvm, gpa, data, len);
 
-	if (kvm_is_error_hva(ghc->hva))
-		return -EFAULT;
-
 	r = __copy_to_user((void __user *)ghc->hva + offset, data, len);
 	if (r)
 		return -EFAULT;
@@ -2238,12 +2238,12 @@ int kvm_read_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
 	if (slots->generation != ghc->generation)
 		__kvm_gfn_to_hva_cache_init(slots, ghc, ghc->gpa, ghc->len);
 
+	if (kvm_is_error_hva(ghc->hva))
+		return -EFAULT;
+
 	if (unlikely(!ghc->memslot))
 		return kvm_read_guest(kvm, ghc->gpa, data, len);
 
-	if (kvm_is_error_hva(ghc->hva))
-		return -EFAULT;
-
 	r = __copy_from_user(data, (void __user *)ghc->hva, len);
 	if (r)
 		return -EFAULT;
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/3] KVM: Clean up __kvm_gfn_to_hva_cache_init() and its callers
  2020-01-09 23:56 [PATCH 0/3] KVM: Clean up guest/host cache read/write code Sean Christopherson
  2020-01-09 23:56 ` [PATCH 1/3] KVM: Check for a bad hva before dropping into the ghc slow path Sean Christopherson
@ 2020-01-09 23:56 ` Sean Christopherson
  2020-01-09 23:56 ` [PATCH 3/3] KVM: Return immediately if __kvm_gfn_to_hva_cache_init() fails Sean Christopherson
  2020-01-21 13:51 ` [PATCH 0/3] KVM: Clean up guest/host cache read/write code Paolo Bonzini
  3 siblings, 0 replies; 5+ messages in thread
From: Sean Christopherson @ 2020-01-09 23:56 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: kvm, linux-kernel, Jim Mattson, Andrew Honig, Barret Rhoden

Barret reported a (technically benign) bug where nr_pages_avail can be
accessed without being initialized if gfn_to_hva_many() fails.

  virt/kvm/kvm_main.c:2193:13: warning: 'nr_pages_avail' may be
  used uninitialized in this function [-Wmaybe-uninitialized]

Rather than simply squashing the warning by initializing nr_pages_avail,
fix the underlying issues by reworking __kvm_gfn_to_hva_cache_init() to
return immediately instead of continuing on.  Now that all callers check
the result and/or bail immediately on a bad hva, there's no need to
explicitly nullify the memslot on error.

Reported-by: Barret Rhoden <brho@google.com>
Fixes: f1b9dd5eb86c ("kvm: Disallow wraparound in kvm_gfn_to_hva_cache_init")
Cc: Jim Mattson <jmattson@google.com>
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
 virt/kvm/kvm_main.c | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index c02c073b9d43..e8d8fc1d72b4 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2155,33 +2155,36 @@ static int __kvm_gfn_to_hva_cache_init(struct kvm_memslots *slots,
 	gfn_t end_gfn = (gpa + len - 1) >> PAGE_SHIFT;
 	gfn_t nr_pages_needed = end_gfn - start_gfn + 1;
 	gfn_t nr_pages_avail;
-	int r = start_gfn <= end_gfn ? 0 : -EINVAL;
 
-	ghc->gpa = gpa;
+	/* Update ghc->generation before performing any error checks. */
 	ghc->generation = slots->generation;
-	ghc->len = len;
-	ghc->hva = KVM_HVA_ERR_BAD;
+
+	if (start_gfn > end_gfn) {
+		ghc->hva = KVM_HVA_ERR_BAD;
+		return -EINVAL;
+	}
 
 	/*
 	 * If the requested region crosses two memslots, we still
 	 * verify that the entire region is valid here.
 	 */
-	while (!r && start_gfn <= end_gfn) {
+	for ( ; start_gfn <= end_gfn; start_gfn += nr_pages_avail) {
 		ghc->memslot = __gfn_to_memslot(slots, start_gfn);
 		ghc->hva = gfn_to_hva_many(ghc->memslot, start_gfn,
 					   &nr_pages_avail);
 		if (kvm_is_error_hva(ghc->hva))
-			r = -EFAULT;
-		start_gfn += nr_pages_avail;
+			return -EFAULT;
 	}
 
 	/* Use the slow path for cross page reads and writes. */
-	if (!r && nr_pages_needed == 1)
+	if (nr_pages_needed == 1)
 		ghc->hva += offset;
 	else
 		ghc->memslot = NULL;
 
-	return r;
+	ghc->gpa = gpa;
+	ghc->len = len;
+	return 0;
 }
 
 int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/3] KVM: Return immediately if __kvm_gfn_to_hva_cache_init() fails
  2020-01-09 23:56 [PATCH 0/3] KVM: Clean up guest/host cache read/write code Sean Christopherson
  2020-01-09 23:56 ` [PATCH 1/3] KVM: Check for a bad hva before dropping into the ghc slow path Sean Christopherson
  2020-01-09 23:56 ` [PATCH 2/3] KVM: Clean up __kvm_gfn_to_hva_cache_init() and its callers Sean Christopherson
@ 2020-01-09 23:56 ` Sean Christopherson
  2020-01-21 13:51 ` [PATCH 0/3] KVM: Clean up guest/host cache read/write code Paolo Bonzini
  3 siblings, 0 replies; 5+ messages in thread
From: Sean Christopherson @ 2020-01-09 23:56 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: kvm, linux-kernel, Jim Mattson, Andrew Honig, Barret Rhoden

Check the result of __kvm_gfn_to_hva_cache_init() and return immediately
instead of relying on the kvm_is_error_hva() check to detect errors so
that it's abundantly clear KVM intends to immediately bail on an error.

Note, the hva check is still mandatory to handle errors on subqeuesnt
calls with the same generation.  Similarly, always return -EFAULT on
error so that multiple (bad) calls for a given generation will get the
same result, e.g. on an illegal gfn wrap, propagating the return from
__kvm_gfn_to_hva_cache_init() would cause the initial call to return
-EINVAL and subsequent calls to return -EFAULT.

Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
 virt/kvm/kvm_main.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index e8d8fc1d72b4..4479dc9ba00a 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2205,8 +2205,10 @@ int kvm_write_guest_offset_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
 
 	BUG_ON(len + offset > ghc->len);
 
-	if (slots->generation != ghc->generation)
-		__kvm_gfn_to_hva_cache_init(slots, ghc, ghc->gpa, ghc->len);
+	if (slots->generation != ghc->generation) {
+		if (__kvm_gfn_to_hva_cache_init(slots, ghc, ghc->gpa, ghc->len))
+			return -EFAULT;
+	}
 
 	if (kvm_is_error_hva(ghc->hva))
 		return -EFAULT;
@@ -2238,8 +2240,10 @@ int kvm_read_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
 
 	BUG_ON(len > ghc->len);
 
-	if (slots->generation != ghc->generation)
-		__kvm_gfn_to_hva_cache_init(slots, ghc, ghc->gpa, ghc->len);
+	if (slots->generation != ghc->generation) {
+		if (__kvm_gfn_to_hva_cache_init(slots, ghc, ghc->gpa, ghc->len))
+			return -EFAULT;
+	}
 
 	if (kvm_is_error_hva(ghc->hva))
 		return -EFAULT;
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/3] KVM: Clean up guest/host cache read/write code
  2020-01-09 23:56 [PATCH 0/3] KVM: Clean up guest/host cache read/write code Sean Christopherson
                   ` (2 preceding siblings ...)
  2020-01-09 23:56 ` [PATCH 3/3] KVM: Return immediately if __kvm_gfn_to_hva_cache_init() fails Sean Christopherson
@ 2020-01-21 13:51 ` Paolo Bonzini
  3 siblings, 0 replies; 5+ messages in thread
From: Paolo Bonzini @ 2020-01-21 13:51 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: kvm, linux-kernel, Jim Mattson, Andrew Honig, Barret Rhoden

On 10/01/20 00:56, Sean Christopherson wrote:
> Minor cleanup to fix the underlying crustiness that led to an uninitialized
> variable warning reported by Barret.
> 
> The first two patches are tagged with Fixes:, but I don't know that they're
> actually worth backporting to stable.  Functionally, everthing works, it's
> just a bit weird and AFAICT not what is intended.  It might be preferable
> to take Barret's patch[*] first and only mark that for stable, as it fixes
> the immediate issue without revamping __kvm_gfn_to_hva_cache_init().
> 
> [*] https://lkml.kernel.org/r/20200109195855.17353-1-brho@google.com
> 
> Sean Christopherson (3):
>   KVM: Check for a bad hva before dropping into the ghc slow path
>   KVM: Clean up __kvm_gfn_to_hva_cache_init() and its callers
>   KVM: Return immediately if __kvm_gfn_to_hva_cache_init() fails
> 
>  virt/kvm/kvm_main.c | 45 ++++++++++++++++++++++++++-------------------
>  1 file changed, 26 insertions(+), 19 deletions(-)
> 

Queued, thanks.

Paolo


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-01-21 13:51 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-09 23:56 [PATCH 0/3] KVM: Clean up guest/host cache read/write code Sean Christopherson
2020-01-09 23:56 ` [PATCH 1/3] KVM: Check for a bad hva before dropping into the ghc slow path Sean Christopherson
2020-01-09 23:56 ` [PATCH 2/3] KVM: Clean up __kvm_gfn_to_hva_cache_init() and its callers Sean Christopherson
2020-01-09 23:56 ` [PATCH 3/3] KVM: Return immediately if __kvm_gfn_to_hva_cache_init() fails Sean Christopherson
2020-01-21 13:51 ` [PATCH 0/3] KVM: Clean up guest/host cache read/write code Paolo Bonzini

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).