linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] KVM: Support guest MAXPHYADDR < host MAXPHYADDR
@ 2020-02-27 17:23 Mohammed Gamal
  2020-02-27 17:23 ` [PATCH 1/5] KVM: x86: Add function to inject guest page fault with reserved bits set Mohammed Gamal
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: Mohammed Gamal @ 2020-02-27 17:23 UTC (permalink / raw)
  To: kvm, pbonzini
  Cc: sean.j.christopherson, vkuznets, wanpengli, jmattson, joro,
	linux-kernel, Mohammed Gamal

When EPT/NPT is enabled, KVM does not really look at guest physical 
address size. Address bits above maximum physical memory size are reserved. 
Because KVM does not look at these guest physical addresses, it currently 
effectively supports guest physical address sizes equal to the host.

This can be problem when having a mixed setup of machines with 5-level page 
tables and machines with 4-level page tables, as live migration can change 
MAXPHYADDR while the guest runs, which can theoretically introduce bugs.

In this patch series we add checks on guest physical addresses in EPT 
violation/misconfig and NPF vmexits and if needed inject the proper 
page faults in the guest.

A more subtle issue is when the host MAXPHYADDR is larger than that of the
guest. Page faults caused by reserved bits on the guest won't cause an EPT
violation/NPF and hence we also check guest MAXPHYADDR and add PFERR_RSVD_MASK
error code to the page fault if needed.


Mohammed Gamal (5):
  KVM: x86: Add function to inject guest page fault with reserved bits
    set
  KVM: VMX: Add guest physical address check in EPT violation and
    misconfig
  KVM: SVM: Add guest physical address check in NPF interception
  KVM: x86: mmu: Move translate_gpa() to mmu.c
  KVM: x86: mmu: Add guest physical address check in translate_gpa()

 arch/x86/include/asm/kvm_host.h |  6 ------
 arch/x86/kvm/mmu/mmu.c          | 10 ++++++++++
 arch/x86/kvm/mmu/paging_tmpl.h  |  2 +-
 arch/x86/kvm/svm.c              |  7 +++++++
 arch/x86/kvm/vmx/vmx.c          | 13 +++++++++++++
 arch/x86/kvm/x86.c              | 14 ++++++++++++++
 arch/x86/kvm/x86.h              |  1 +
 7 files changed, 46 insertions(+), 7 deletions(-)

-- 
2.21.1


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

* [PATCH 1/5] KVM: x86: Add function to inject guest page fault with reserved bits set
  2020-02-27 17:23 [PATCH 0/5] KVM: Support guest MAXPHYADDR < host MAXPHYADDR Mohammed Gamal
@ 2020-02-27 17:23 ` Mohammed Gamal
  2020-02-27 19:30   ` Ben Gardon
  2020-02-28 22:29   ` Sean Christopherson
  2020-02-27 17:23 ` [PATCH 2/5] KVM: VMX: Add guest physical address check in EPT violation and misconfig Mohammed Gamal
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 13+ messages in thread
From: Mohammed Gamal @ 2020-02-27 17:23 UTC (permalink / raw)
  To: kvm, pbonzini
  Cc: sean.j.christopherson, vkuznets, wanpengli, jmattson, joro,
	linux-kernel, Mohammed Gamal

Signed-off-by: Mohammed Gamal <mgamal@redhat.com>
---
 arch/x86/kvm/x86.c | 14 ++++++++++++++
 arch/x86/kvm/x86.h |  1 +
 2 files changed, 15 insertions(+)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 359fcd395132..434c55a8b719 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10494,6 +10494,20 @@ u64 kvm_spec_ctrl_valid_bits(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_spec_ctrl_valid_bits);
 
+void kvm_inject_rsvd_bits_pf(struct kvm_vcpu *vcpu, gpa_t gpa)
+{
+	struct x86_exception fault;
+
+	fault.vector = PF_VECTOR;
+	fault.error_code_valid = true;
+	fault.error_code = PFERR_RSVD_MASK;
+	fault.nested_page_fault = false;
+	fault.address = gpa;
+
+	kvm_inject_page_fault(vcpu, &fault);
+}
+EXPORT_SYMBOL_GPL(kvm_inject_rsvd_bits_pf);
+
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_fast_mmio);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq);
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index 3624665acee4..7d8ab28a6983 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -276,6 +276,7 @@ int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
 bool kvm_mtrr_check_gfn_range_consistency(struct kvm_vcpu *vcpu, gfn_t gfn,
 					  int page_num);
 bool kvm_vector_hashing_enabled(void);
+void kvm_inject_rsvd_bits_pf(struct kvm_vcpu *vcpu, gpa_t gpa);
 int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
 			    int emulation_type, void *insn, int insn_len);
 enum exit_fastpath_completion handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu);
-- 
2.21.1


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

* [PATCH 2/5] KVM: VMX: Add guest physical address check in EPT violation and misconfig
  2020-02-27 17:23 [PATCH 0/5] KVM: Support guest MAXPHYADDR < host MAXPHYADDR Mohammed Gamal
  2020-02-27 17:23 ` [PATCH 1/5] KVM: x86: Add function to inject guest page fault with reserved bits set Mohammed Gamal
@ 2020-02-27 17:23 ` Mohammed Gamal
  2020-02-27 17:55   ` Jim Mattson
  2020-02-27 17:23 ` [PATCH 3/5] KVM: SVM: Add guest physical address check in NPF interception Mohammed Gamal
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Mohammed Gamal @ 2020-02-27 17:23 UTC (permalink / raw)
  To: kvm, pbonzini
  Cc: sean.j.christopherson, vkuznets, wanpengli, jmattson, joro,
	linux-kernel, Mohammed Gamal

Check guest physical address against it's maximum physical memory. If
the guest's physical address exceeds the maximum (i.e. has reserved bits
set), inject a guest page fault with PFERR_RSVD_MASK.

Signed-off-by: Mohammed Gamal <mgamal@redhat.com>
---
 arch/x86/kvm/vmx/vmx.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 63aaf44edd1f..477d196aa235 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -5162,6 +5162,12 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu)
 	gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
 	trace_kvm_page_fault(gpa, exit_qualification);
 
+	/* Check if guest gpa doesn't exceed physical memory limits */
+	if (gpa >= (1ull << cpuid_maxphyaddr(vcpu))) {
+		kvm_inject_rsvd_bits_pf(vcpu, gpa);
+		return 1;
+	}
+
 	/* Is it a read fault? */
 	error_code = (exit_qualification & EPT_VIOLATION_ACC_READ)
 		     ? PFERR_USER_MASK : 0;
@@ -5193,6 +5199,13 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu)
 	 * nGPA here instead of the required GPA.
 	 */
 	gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
+
+	/* Check if guest gpa doesn't exceed physical memory limits */
+	if (gpa >= (1ull << cpuid_maxphyaddr(vcpu))) {
+		kvm_inject_rsvd_bits_pf(vcpu, gpa);
+		return 1;
+	}
+
 	if (!is_guest_mode(vcpu) &&
 	    !kvm_io_bus_write(vcpu, KVM_FAST_MMIO_BUS, gpa, 0, NULL)) {
 		trace_kvm_fast_mmio(gpa);
-- 
2.21.1


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

* [PATCH 3/5] KVM: SVM: Add guest physical address check in NPF interception
  2020-02-27 17:23 [PATCH 0/5] KVM: Support guest MAXPHYADDR < host MAXPHYADDR Mohammed Gamal
  2020-02-27 17:23 ` [PATCH 1/5] KVM: x86: Add function to inject guest page fault with reserved bits set Mohammed Gamal
  2020-02-27 17:23 ` [PATCH 2/5] KVM: VMX: Add guest physical address check in EPT violation and misconfig Mohammed Gamal
@ 2020-02-27 17:23 ` Mohammed Gamal
  2020-02-27 17:23 ` [PATCH 4/5] KVM: x86: mmu: Move translate_gpa() to mmu.c Mohammed Gamal
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 13+ messages in thread
From: Mohammed Gamal @ 2020-02-27 17:23 UTC (permalink / raw)
  To: kvm, pbonzini
  Cc: sean.j.christopherson, vkuznets, wanpengli, jmattson, joro,
	linux-kernel, Mohammed Gamal

Check guest physical address against it's maximum physical memory. If
the guest's physical address exceeds the maximum (i.e. has reserved bits
set), inject a guest page fault with PFERR_RSVD_MASK.

Signed-off-by: Mohammed Gamal <mgamal@redhat.com>
---
 arch/x86/kvm/svm.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index ad3f5b178a03..facd9b0c9fb0 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -2754,6 +2754,13 @@ static int npf_interception(struct vcpu_svm *svm)
 	u64 error_code = svm->vmcb->control.exit_info_1;
 
 	trace_kvm_page_fault(fault_address, error_code);
+
+	/* Check if guest gpa doesn't exceed physical memory limits */
+	if (fault_address >= (1ull << cpuid_maxphyaddr(&svm->vcpu))) {
+		kvm_inject_rsvd_bits_pf(&svm->vcpu, fault_address);
+		return 1;
+	}
+
 	return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code,
 			static_cpu_has(X86_FEATURE_DECODEASSISTS) ?
 			svm->vmcb->control.insn_bytes : NULL,
-- 
2.21.1


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

* [PATCH 4/5] KVM: x86: mmu: Move translate_gpa() to mmu.c
  2020-02-27 17:23 [PATCH 0/5] KVM: Support guest MAXPHYADDR < host MAXPHYADDR Mohammed Gamal
                   ` (2 preceding siblings ...)
  2020-02-27 17:23 ` [PATCH 3/5] KVM: SVM: Add guest physical address check in NPF interception Mohammed Gamal
@ 2020-02-27 17:23 ` Mohammed Gamal
  2020-02-27 17:23 ` [PATCH 5/5] KVM: x86: mmu: Add guest physical address check in translate_gpa() Mohammed Gamal
  2020-02-27 17:58 ` [PATCH 0/5] KVM: Support guest MAXPHYADDR < host MAXPHYADDR Jim Mattson
  5 siblings, 0 replies; 13+ messages in thread
From: Mohammed Gamal @ 2020-02-27 17:23 UTC (permalink / raw)
  To: kvm, pbonzini
  Cc: sean.j.christopherson, vkuznets, wanpengli, jmattson, joro,
	linux-kernel, Mohammed Gamal

Also no point of it being inline since it's always called through
function pointers. So remove that.

Signed-off-by: Mohammed Gamal <mgamal@redhat.com>
---
 arch/x86/include/asm/kvm_host.h | 6 ------
 arch/x86/kvm/mmu/mmu.c          | 6 ++++++
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 98959e8cd448..683663b437e6 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1515,12 +1515,6 @@ void kvm_mmu_new_cr3(struct kvm_vcpu *vcpu, gpa_t new_cr3, bool skip_tlb_flush);
 void kvm_enable_tdp(void);
 void kvm_disable_tdp(void);
 
-static inline gpa_t translate_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access,
-				  struct x86_exception *exception)
-{
-	return gpa;
-}
-
 static inline struct kvm_mmu_page *page_header(hpa_t shadow_page)
 {
 	struct page *page = pfn_to_page(shadow_page >> PAGE_SHIFT);
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 87e9ba27ada1..099643edfdeb 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -520,6 +520,12 @@ static bool check_mmio_spte(struct kvm_vcpu *vcpu, u64 spte)
 	return likely(kvm_gen == spte_gen);
 }
 
+static gpa_t translate_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access,
+                                  struct x86_exception *exception)
+{
+        return gpa;
+}
+
 /*
  * Sets the shadow PTE masks used by the MMU.
  *
-- 
2.21.1


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

* [PATCH 5/5] KVM: x86: mmu: Add guest physical address check in translate_gpa()
  2020-02-27 17:23 [PATCH 0/5] KVM: Support guest MAXPHYADDR < host MAXPHYADDR Mohammed Gamal
                   ` (3 preceding siblings ...)
  2020-02-27 17:23 ` [PATCH 4/5] KVM: x86: mmu: Move translate_gpa() to mmu.c Mohammed Gamal
@ 2020-02-27 17:23 ` Mohammed Gamal
  2020-02-27 18:00   ` Paolo Bonzini
  2020-02-27 17:58 ` [PATCH 0/5] KVM: Support guest MAXPHYADDR < host MAXPHYADDR Jim Mattson
  5 siblings, 1 reply; 13+ messages in thread
From: Mohammed Gamal @ 2020-02-27 17:23 UTC (permalink / raw)
  To: kvm, pbonzini
  Cc: sean.j.christopherson, vkuznets, wanpengli, jmattson, joro,
	linux-kernel, Mohammed Gamal

In case of running a guest with 4-level page tables on a 5-level page
table host, it might happen that a guest might have a physical address
with reserved bits set, but the host won't see that and trap it.

Hence, we need to check page faults' physical addresses against the guest's
maximum physical memory and if it's exceeded, we need to add
the PFERR_RSVD_MASK bits to the PF's error code.

Also make sure the error code isn't overwritten by the page table walker.

Signed-off-by: Mohammed Gamal <mgamal@redhat.com>
---
 arch/x86/kvm/mmu/mmu.c         | 4 ++++
 arch/x86/kvm/mmu/paging_tmpl.h | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 099643edfdeb..994e8377b65f 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -523,6 +523,10 @@ static bool check_mmio_spte(struct kvm_vcpu *vcpu, u64 spte)
 static gpa_t translate_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u32 access,
                                   struct x86_exception *exception)
 {
+	/* Check if guest physical address doesn't exceed guest maximum */
+	if (gpa >= (1ull << cpuid_maxphyaddr(vcpu)))
+		exception->error_code |= PFERR_RSVD_MASK;
+
         return gpa;
 }
 
diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h
index e4c8a4cbf407..aa3db722604b 100644
--- a/arch/x86/kvm/mmu/paging_tmpl.h
+++ b/arch/x86/kvm/mmu/paging_tmpl.h
@@ -476,7 +476,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
 
 	walker->fault.vector = PF_VECTOR;
 	walker->fault.error_code_valid = true;
-	walker->fault.error_code = errcode;
+	walker->fault.error_code |= errcode;
 
 #if PTTYPE == PTTYPE_EPT
 	/*
-- 
2.21.1


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

* Re: [PATCH 2/5] KVM: VMX: Add guest physical address check in EPT violation and misconfig
  2020-02-27 17:23 ` [PATCH 2/5] KVM: VMX: Add guest physical address check in EPT violation and misconfig Mohammed Gamal
@ 2020-02-27 17:55   ` Jim Mattson
  2020-02-28 22:36     ` Sean Christopherson
  0 siblings, 1 reply; 13+ messages in thread
From: Jim Mattson @ 2020-02-27 17:55 UTC (permalink / raw)
  To: Mohammed Gamal
  Cc: kvm list, Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov,
	Wanpeng Li, Joerg Roedel, LKML

On Thu, Feb 27, 2020 at 9:23 AM Mohammed Gamal <mgamal@redhat.com> wrote:
>
> Check guest physical address against it's maximum physical memory. If
Nit: "its," without an apostrophe.

> the guest's physical address exceeds the maximum (i.e. has reserved bits
> set), inject a guest page fault with PFERR_RSVD_MASK.
>
> Signed-off-by: Mohammed Gamal <mgamal@redhat.com>
> ---
>  arch/x86/kvm/vmx/vmx.c | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
>
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index 63aaf44edd1f..477d196aa235 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -5162,6 +5162,12 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu)
>         gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
>         trace_kvm_page_fault(gpa, exit_qualification);
>
> +       /* Check if guest gpa doesn't exceed physical memory limits */
> +       if (gpa >= (1ull << cpuid_maxphyaddr(vcpu))) {
> +               kvm_inject_rsvd_bits_pf(vcpu, gpa);

Even if PFERR_RSVD_MASK is set in the page fault error code, shouldn't
we set still conditionally set:
    PFERR_WRITE_MASK - for an attempted write
    PFERR_USER_MASK - for a usermode access
    PFERR_FETCH_MASK - for an instruction fetch

> +               return 1;
> +       }
> +
>         /* Is it a read fault? */
>         error_code = (exit_qualification & EPT_VIOLATION_ACC_READ)
>                      ? PFERR_USER_MASK : 0;
> @@ -5193,6 +5199,13 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu)
>          * nGPA here instead of the required GPA.
>          */
>         gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
> +
> +       /* Check if guest gpa doesn't exceed physical memory limits */
> +       if (gpa >= (1ull << cpuid_maxphyaddr(vcpu))) {
> +               kvm_inject_rsvd_bits_pf(vcpu, gpa);

And here as well?

> +               return 1;
> +       }
> +
>         if (!is_guest_mode(vcpu) &&
>             !kvm_io_bus_write(vcpu, KVM_FAST_MMIO_BUS, gpa, 0, NULL)) {
>                 trace_kvm_fast_mmio(gpa);
> --
> 2.21.1
>

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

* Re: [PATCH 0/5] KVM: Support guest MAXPHYADDR < host MAXPHYADDR
  2020-02-27 17:23 [PATCH 0/5] KVM: Support guest MAXPHYADDR < host MAXPHYADDR Mohammed Gamal
                   ` (4 preceding siblings ...)
  2020-02-27 17:23 ` [PATCH 5/5] KVM: x86: mmu: Add guest physical address check in translate_gpa() Mohammed Gamal
@ 2020-02-27 17:58 ` Jim Mattson
  5 siblings, 0 replies; 13+ messages in thread
From: Jim Mattson @ 2020-02-27 17:58 UTC (permalink / raw)
  To: Mohammed Gamal
  Cc: kvm list, Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov,
	Wanpeng Li, Joerg Roedel, LKML

On Thu, Feb 27, 2020 at 9:23 AM Mohammed Gamal <mgamal@redhat.com> wrote:
>
> When EPT/NPT is enabled, KVM does not really look at guest physical
> address size. Address bits above maximum physical memory size are reserved.
> Because KVM does not look at these guest physical addresses, it currently
> effectively supports guest physical address sizes equal to the host.
>
> This can be problem when having a mixed setup of machines with 5-level page
> tables and machines with 4-level page tables, as live migration can change
> MAXPHYADDR while the guest runs, which can theoretically introduce bugs.
>
> In this patch series we add checks on guest physical addresses in EPT
> violation/misconfig and NPF vmexits and if needed inject the proper
> page faults in the guest.
>
> A more subtle issue is when the host MAXPHYADDR is larger than that of the
> guest. Page faults caused by reserved bits on the guest won't cause an EPT
> violation/NPF and hence we also check guest MAXPHYADDR and add PFERR_RSVD_MASK
> error code to the page fault if needed.

What about the #GP that should be delivered if any reserved bits are
set in any of the 4 PDPTRs when the guest loads CR3 in PAE mode?

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

* Re: [PATCH 5/5] KVM: x86: mmu: Add guest physical address check in translate_gpa()
  2020-02-27 17:23 ` [PATCH 5/5] KVM: x86: mmu: Add guest physical address check in translate_gpa() Mohammed Gamal
@ 2020-02-27 18:00   ` Paolo Bonzini
  2020-02-28 22:26     ` Sean Christopherson
  0 siblings, 1 reply; 13+ messages in thread
From: Paolo Bonzini @ 2020-02-27 18:00 UTC (permalink / raw)
  To: Mohammed Gamal, kvm
  Cc: sean.j.christopherson, vkuznets, wanpengli, jmattson, joro, linux-kernel

On 27/02/20 18:23, Mohammed Gamal wrote:
> In case of running a guest with 4-level page tables on a 5-level page
> table host, it might happen that a guest might have a physical address
> with reserved bits set, but the host won't see that and trap it.
> 
> Hence, we need to check page faults' physical addresses against the guest's
> maximum physical memory and if it's exceeded, we need to add
> the PFERR_RSVD_MASK bits to the PF's error code.

You can just set it to PFERR_RSVD_MASK | PFERR_PRESENT_MASK (no need to
use an "|") and return UNMAPPED_GBA.  But I would have thought that this
is not needed and the

                if (unlikely(FNAME(is_rsvd_bits_set)(mmu, pte, walker->level))) {
                        errcode = PFERR_RSVD_MASK | PFERR_PRESENT_MASK;
                        goto error;
                }

code would have catch the reserved bits.

> Also make sure the error code isn't overwritten by the page table walker.

Returning UNMAPPED_GVA would remove that as well.

I'm not sure this patch is enough however.  For a usermode access with
"!pte.u pte.40" for example you should be getting:

- a #PF with PRESENT|USER error code on a machine with physical address
width >=41; in this case you don't get an EPT violation or misconfig.

- a #PF with RSVD error code on a machine with physical address with <41.

You can enable verbose mode in access.c to see if this case is being generated,
and if so debug it.

The solution for this would be to trap page faults and do a page table
walk (with vcpu->arch.walk_mmu->gva_to_gpa) to find the correct error
code.

Paolo


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

* Re: [PATCH 1/5] KVM: x86: Add function to inject guest page fault with reserved bits set
  2020-02-27 17:23 ` [PATCH 1/5] KVM: x86: Add function to inject guest page fault with reserved bits set Mohammed Gamal
@ 2020-02-27 19:30   ` Ben Gardon
  2020-02-28 22:29   ` Sean Christopherson
  1 sibling, 0 replies; 13+ messages in thread
From: Ben Gardon @ 2020-02-27 19:30 UTC (permalink / raw)
  To: Mohammed Gamal
  Cc: kvm, Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov,
	wanpengli, Jim Mattson, joro, linux-kernel

On Thu, Feb 27, 2020 at 9:23 AM Mohammed Gamal <mgamal@redhat.com> wrote:
>
> Signed-off-by: Mohammed Gamal <mgamal@redhat.com>
> ---
>  arch/x86/kvm/x86.c | 14 ++++++++++++++
>  arch/x86/kvm/x86.h |  1 +
>  2 files changed, 15 insertions(+)
>
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 359fcd395132..434c55a8b719 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -10494,6 +10494,20 @@ u64 kvm_spec_ctrl_valid_bits(struct kvm_vcpu *vcpu)
>  }
>  EXPORT_SYMBOL_GPL(kvm_spec_ctrl_valid_bits);
>
> +void kvm_inject_rsvd_bits_pf(struct kvm_vcpu *vcpu, gpa_t gpa)
> +{
> +       struct x86_exception fault;
> +
> +       fault.vector = PF_VECTOR;
> +       fault.error_code_valid = true;
> +       fault.error_code = PFERR_RSVD_MASK;
> +       fault.nested_page_fault = false;
> +       fault.address = gpa;
> +
> +       kvm_inject_page_fault(vcpu, &fault);
> +}
> +EXPORT_SYMBOL_GPL(kvm_inject_rsvd_bits_pf);
> +

There are calls to kvm_mmu_page_fault in arch/x86/kvm/mmu/mmu.c that
don't get the check and injected page fault in the later patches in
this series. Is the check not needed in those cases?

>  EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit);
>  EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_fast_mmio);
>  EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq);
> diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
> index 3624665acee4..7d8ab28a6983 100644
> --- a/arch/x86/kvm/x86.h
> +++ b/arch/x86/kvm/x86.h
> @@ -276,6 +276,7 @@ int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
>  bool kvm_mtrr_check_gfn_range_consistency(struct kvm_vcpu *vcpu, gfn_t gfn,
>                                           int page_num);
>  bool kvm_vector_hashing_enabled(void);
> +void kvm_inject_rsvd_bits_pf(struct kvm_vcpu *vcpu, gpa_t gpa);
>  int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
>                             int emulation_type, void *insn, int insn_len);
>  enum exit_fastpath_completion handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu);
> --
> 2.21.1
>

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

* Re: [PATCH 5/5] KVM: x86: mmu: Add guest physical address check in translate_gpa()
  2020-02-27 18:00   ` Paolo Bonzini
@ 2020-02-28 22:26     ` Sean Christopherson
  0 siblings, 0 replies; 13+ messages in thread
From: Sean Christopherson @ 2020-02-28 22:26 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Mohammed Gamal, kvm, vkuznets, wanpengli, jmattson, joro, linux-kernel

On Thu, Feb 27, 2020 at 07:00:33PM +0100, Paolo Bonzini wrote:
> On 27/02/20 18:23, Mohammed Gamal wrote:
> > In case of running a guest with 4-level page tables on a 5-level page
> > table host, it might happen that a guest might have a physical address
> > with reserved bits set, but the host won't see that and trap it.
> > 
> > Hence, we need to check page faults' physical addresses against the guest's
> > maximum physical memory and if it's exceeded, we need to add
> > the PFERR_RSVD_MASK bits to the PF's error code.
> 
> You can just set it to PFERR_RSVD_MASK | PFERR_PRESENT_MASK (no need to
> use an "|") and return UNMAPPED_GBA.  But I would have thought that this
> is not needed and the
> 
>                 if (unlikely(FNAME(is_rsvd_bits_set)(mmu, pte, walker->level))) {
>                         errcode = PFERR_RSVD_MASK | PFERR_PRESENT_MASK;
>                         goto error;
>                 }
> 
> code would have catch the reserved bits.

That would be my assumption as well.  The only manual check should be in
the top level EPT and NPT handlers.

> > Also make sure the error code isn't overwritten by the page table walker.
> 
> Returning UNMAPPED_GVA would remove that as well.
> 
> I'm not sure this patch is enough however.  For a usermode access with
> "!pte.u pte.40" for example you should be getting:
> 
> - a #PF with PRESENT|USER error code on a machine with physical address
> width >=41; in this case you don't get an EPT violation or misconfig.
> 
> - a #PF with RSVD error code on a machine with physical address with <41.
> 
> You can enable verbose mode in access.c to see if this case is being generated,
> and if so debug it.
> 
> The solution for this would be to trap page faults and do a page table
> walk (with vcpu->arch.walk_mmu->gva_to_gpa) to find the correct error
> code.
> 
> Paolo
> 

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

* Re: [PATCH 1/5] KVM: x86: Add function to inject guest page fault with reserved bits set
  2020-02-27 17:23 ` [PATCH 1/5] KVM: x86: Add function to inject guest page fault with reserved bits set Mohammed Gamal
  2020-02-27 19:30   ` Ben Gardon
@ 2020-02-28 22:29   ` Sean Christopherson
  1 sibling, 0 replies; 13+ messages in thread
From: Sean Christopherson @ 2020-02-28 22:29 UTC (permalink / raw)
  To: Mohammed Gamal
  Cc: kvm, pbonzini, vkuznets, wanpengli, jmattson, joro, linux-kernel

On Thu, Feb 27, 2020 at 07:23:02PM +0200, Mohammed Gamal wrote:
> Signed-off-by: Mohammed Gamal <mgamal@redhat.com>
> ---
>  arch/x86/kvm/x86.c | 14 ++++++++++++++
>  arch/x86/kvm/x86.h |  1 +
>  2 files changed, 15 insertions(+)
> 
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 359fcd395132..434c55a8b719 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -10494,6 +10494,20 @@ u64 kvm_spec_ctrl_valid_bits(struct kvm_vcpu *vcpu)
>  }
>  EXPORT_SYMBOL_GPL(kvm_spec_ctrl_valid_bits);
>  
> +void kvm_inject_rsvd_bits_pf(struct kvm_vcpu *vcpu, gpa_t gpa)
> +{
> +	struct x86_exception fault;
> +
> +	fault.vector = PF_VECTOR;
> +	fault.error_code_valid = true;
> +	fault.error_code = PFERR_RSVD_MASK;

As Jim pointed out, by definition this is PRESENT.  Other bits needs to
be translated from the VMCS.EXIT_QUALIFICATION field and/or manually
calculated for EPT.  I assume NPT is more or less good to go, i.e. just
pass in the error_code?

> +	fault.nested_page_fault = false;
> +	fault.address = gpa;

Taking the GPA is wrong, @address is CR3, a GVA.

> +	kvm_inject_page_fault(vcpu, &fault);

This needs to be

	vcpu->arch.walk_mmu->inject_page_fault(vcpu, &fault);

so that L1 (nested VMX) can intercept the #PF.

> +}
> +EXPORT_SYMBOL_GPL(kvm_inject_rsvd_bits_pf);
> +
>  EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit);
>  EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_fast_mmio);
>  EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq);
> diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
> index 3624665acee4..7d8ab28a6983 100644
> --- a/arch/x86/kvm/x86.h
> +++ b/arch/x86/kvm/x86.h
> @@ -276,6 +276,7 @@ int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
>  bool kvm_mtrr_check_gfn_range_consistency(struct kvm_vcpu *vcpu, gfn_t gfn,
>  					  int page_num);
>  bool kvm_vector_hashing_enabled(void);
> +void kvm_inject_rsvd_bits_pf(struct kvm_vcpu *vcpu, gpa_t gpa);
>  int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
>  			    int emulation_type, void *insn, int insn_len);
>  enum exit_fastpath_completion handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu);
> -- 
> 2.21.1
> 

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

* Re: [PATCH 2/5] KVM: VMX: Add guest physical address check in EPT violation and misconfig
  2020-02-27 17:55   ` Jim Mattson
@ 2020-02-28 22:36     ` Sean Christopherson
  0 siblings, 0 replies; 13+ messages in thread
From: Sean Christopherson @ 2020-02-28 22:36 UTC (permalink / raw)
  To: Jim Mattson
  Cc: Mohammed Gamal, kvm list, Paolo Bonzini, Vitaly Kuznetsov,
	Wanpeng Li, Joerg Roedel, LKML

On Thu, Feb 27, 2020 at 09:55:32AM -0800, Jim Mattson wrote:
> On Thu, Feb 27, 2020 at 9:23 AM Mohammed Gamal <mgamal@redhat.com> wrote:
> >
> > Check guest physical address against it's maximum physical memory. If
> Nit: "its," without an apostrophe.
> 
> > the guest's physical address exceeds the maximum (i.e. has reserved bits
> > set), inject a guest page fault with PFERR_RSVD_MASK.

Wish I had actually read this series when it first flew by, just spent
several hours debugging this exact thing when running the "access" test.

> > Signed-off-by: Mohammed Gamal <mgamal@redhat.com>
> > ---
> >  arch/x86/kvm/vmx/vmx.c | 13 +++++++++++++
> >  1 file changed, 13 insertions(+)
> >
> > diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> > index 63aaf44edd1f..477d196aa235 100644
> > --- a/arch/x86/kvm/vmx/vmx.c
> > +++ b/arch/x86/kvm/vmx/vmx.c
> > @@ -5162,6 +5162,12 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu)
> >         gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
> >         trace_kvm_page_fault(gpa, exit_qualification);
> >
> > +       /* Check if guest gpa doesn't exceed physical memory limits */
> > +       if (gpa >= (1ull << cpuid_maxphyaddr(vcpu))) {

Add a helper for this, it's easier than copy-pasting the comment and code
everywhere.  BIT_ULL() is also handy.

static inline bool kvm_mmu_is_illegal_gpa(gpa_t gpa)
{
	return (gpa < BIT_ULL(cpuid_maxphyaddr(vcpu)));
}

> > +               kvm_inject_rsvd_bits_pf(vcpu, gpa);
> 
> Even if PFERR_RSVD_MASK is set in the page fault error code, shouldn't
> we set still conditionally set:
>     PFERR_WRITE_MASK - for an attempted write
>     PFERR_USER_MASK - for a usermode access
>     PFERR_FETCH_MASK - for an instruction fetch

Yep.  Move this down below where error_code is calculated.  Then the code
should be something like this.  Not fun to handle this with EPT :-(

Note, VMCS.GUEST_LINEAR_ADDRESS isn't guaranteed to be accurate, e.g. if
the guest is putting bad gpas into Intel PT, but I don't think we have any
choice but to blindly cram it in and hope for the best.

	if (unlikely(kvm_mmu_is_illegal_gpa(vcpu, gpa))) {
		/* Morph the EPT error code into a #PF error code. */
		error_code &= ~(PFERR_USER_MASK | PFERR_GUEST_FINAL_MASK |
				PFERR_GUEST_PAGE_MASK);
		if (vmx_get_cpl(vcpu) == 3)
			error_code |= PFERR_USER_MASK;
		error_code |= PFERR_PRESENT_MASK;

		kvm_inject_rsvd_bits_pf(vcpu, vmcs_readl(GUEST_LINEAR_ADDRESS),
					error_code);

		return 1;
	}

 
> > +               return 1;
> > +       }
> > +
> >         /* Is it a read fault? */
> >         error_code = (exit_qualification & EPT_VIOLATION_ACC_READ)
> >                      ? PFERR_USER_MASK : 0;
> > @@ -5193,6 +5199,13 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu)
> >          * nGPA here instead of the required GPA.
> >          */
> >         gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
> > +
> > +       /* Check if guest gpa doesn't exceed physical memory limits */
> > +       if (gpa >= (1ull << cpuid_maxphyaddr(vcpu))) {
> > +               kvm_inject_rsvd_bits_pf(vcpu, gpa);
> 
> And here as well?

This shouldn't happen.  If KVM creates a bad EPTE for an illegal GPA, we
done goofed up.  I.e.

	if (WARN_ON_ONCE(kvm_mmu_is_illegal_gpa(vcpu, gpa))) {
		vcpu->run->blah = blah;
		return 0;
	}

> 
> > +               return 1;
> > +       }
> > +
> >         if (!is_guest_mode(vcpu) &&
> >             !kvm_io_bus_write(vcpu, KVM_FAST_MMIO_BUS, gpa, 0, NULL)) {
> >                 trace_kvm_fast_mmio(gpa);
> > --
> > 2.21.1
> >

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

end of thread, other threads:[~2020-02-28 22:36 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-27 17:23 [PATCH 0/5] KVM: Support guest MAXPHYADDR < host MAXPHYADDR Mohammed Gamal
2020-02-27 17:23 ` [PATCH 1/5] KVM: x86: Add function to inject guest page fault with reserved bits set Mohammed Gamal
2020-02-27 19:30   ` Ben Gardon
2020-02-28 22:29   ` Sean Christopherson
2020-02-27 17:23 ` [PATCH 2/5] KVM: VMX: Add guest physical address check in EPT violation and misconfig Mohammed Gamal
2020-02-27 17:55   ` Jim Mattson
2020-02-28 22:36     ` Sean Christopherson
2020-02-27 17:23 ` [PATCH 3/5] KVM: SVM: Add guest physical address check in NPF interception Mohammed Gamal
2020-02-27 17:23 ` [PATCH 4/5] KVM: x86: mmu: Move translate_gpa() to mmu.c Mohammed Gamal
2020-02-27 17:23 ` [PATCH 5/5] KVM: x86: mmu: Add guest physical address check in translate_gpa() Mohammed Gamal
2020-02-27 18:00   ` Paolo Bonzini
2020-02-28 22:26     ` Sean Christopherson
2020-02-27 17:58 ` [PATCH 0/5] KVM: Support guest MAXPHYADDR < host MAXPHYADDR Jim Mattson

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