* [PATCH 0/4] MIPS: KVM: Fix MMU/TLB management issues
@ 2016-08-11 10:52 James Hogan
2016-08-11 10:58 ` [PATCH 1/4] MIPS: KVM: Fix mapped fault broken commpage handling James Hogan
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: James Hogan @ 2016-08-11 10:52 UTC (permalink / raw)
To: Paolo Bonzini
Cc: James Hogan, Radim Krčmář, Ralf Baechle,
linux-mips, kvm, stable
These patches fix several issues in the management of MIPS KVM TLB
faults:
1) kvm_mips_handle_mapped_seg_tlb_fault() misbehaves for virtual address
zero, which can be hit if the guest creates such a mapping and
accesses it in a way unexpected for the commpage (e.g. a CACHE
instruction).
2) kvm_mips_handle_mapped_seg_tlb_fault() doesn't range check the gfn,
allowing a high mapping by the guest to overflow the guest_pmap[].
3) kvm_mips_handle_kseg0_tlb_fault() has an off by one in its gfn range
check, which could allow an odd sized guest_pmap[] to be overflowed.
4) some callers of kvm_mips_handle_kseg0_tlb_fault() and
kvm_mips_handle_mapped_seg_tlb_fault() don't correctly propagate
errors upwards.
They're all marked for stable but won't apply cleanly before v4.8-rc1
due to recent changes. I have backports ready though.
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Radim Krčmář" <rkrcmar@redhat.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: kvm@vger.kernel.org
Cc: <stable@vger.kernel.org>
James Hogan (4):
MIPS: KVM: Fix mapped fault broken commpage handling
MIPS: KVM: Add missing gfn range check
MIPS: KVM: Fix gfn range check in kseg0 tlb faults
MIPS: KVM: Propagate kseg0/mapped tlb fault errors
arch/mips/kvm/emulate.c | 35 ++++++++++++++++------
arch/mips/kvm/mmu.c | 68 +++++++++++++++++++++++++++---------------
2 files changed, 70 insertions(+), 33 deletions(-)
--
git-series 0.8.7
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/4] MIPS: KVM: Fix mapped fault broken commpage handling
2016-08-11 10:52 [PATCH 0/4] MIPS: KVM: Fix MMU/TLB management issues James Hogan
@ 2016-08-11 10:58 ` James Hogan
2016-08-11 10:58 ` [PATCH 2/4] MIPS: KVM: Add missing gfn range check James Hogan
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: James Hogan @ 2016-08-11 10:58 UTC (permalink / raw)
To: Paolo Bonzini
Cc: Radim Krčmář, Ralf Baechle, linux-mips, kvm,
stable, James Hogan
kvm_mips_handle_mapped_seg_tlb_fault() appears to map the guest page at
virtual address 0 to PFN 0 if the guest has created its own mapping
there. The intention is unclear, but it may have been an attempt to
protect the zero page from being mapped to anything but the comm page in
code paths you wouldn't expect from genuine commpage accesses (guest
kernel mode cache instructions on that address, hitting trapping
instructions when executing from that address with a coincidental TLB
eviction during the KVM handling, and guest user mode accesses to that
address).
Fix this to check for mappings exactly at KVM_GUEST_COMMPAGE_ADDR (it
may not be at address 0 since commit 42aa12e74e91 ("MIPS: KVM: Move
commpage so 0x0 is unmapped")), and set the corresponding EntryLo to be
interpreted as 0 (invalid).
Fixes: 858dd5d45733 ("KVM/MIPS32: MMU/TLB operations for the Guest.")
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Radim Krčmář" <rkrcmar@redhat.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: kvm@vger.kernel.org
Cc: <stable@vger.kernel.org> # 3.10.x-
---
arch/mips/kvm/mmu.c | 49 ++++++++++++++++++++++++++--------------------
1 file changed, 28 insertions(+), 21 deletions(-)
diff --git a/arch/mips/kvm/mmu.c b/arch/mips/kvm/mmu.c
index 57319ee57c4f..96e0b24cfe5c 100644
--- a/arch/mips/kvm/mmu.c
+++ b/arch/mips/kvm/mmu.c
@@ -138,35 +138,42 @@ int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu,
unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
struct kvm *kvm = vcpu->kvm;
kvm_pfn_t pfn0, pfn1;
+ long tlb_lo[2];
int ret;
- if ((tlb->tlb_hi & VPN2_MASK) == 0) {
- pfn0 = 0;
- pfn1 = 0;
- } else {
- if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo[0])
- >> PAGE_SHIFT) < 0)
- return -1;
-
- if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb->tlb_lo[1])
- >> PAGE_SHIFT) < 0)
- return -1;
-
- pfn0 = kvm->arch.guest_pmap[
- mips3_tlbpfn_to_paddr(tlb->tlb_lo[0]) >> PAGE_SHIFT];
- pfn1 = kvm->arch.guest_pmap[
- mips3_tlbpfn_to_paddr(tlb->tlb_lo[1]) >> PAGE_SHIFT];
- }
+ tlb_lo[0] = tlb->tlb_lo[0];
+ tlb_lo[1] = tlb->tlb_lo[1];
+
+ /*
+ * The commpage address must not be mapped to anything else if the guest
+ * TLB contains entries nearby, or commpage accesses will break.
+ */
+ if (!((tlb->tlb_hi ^ KVM_GUEST_COMMPAGE_ADDR) &
+ VPN2_MASK & (PAGE_MASK << 1)))
+ tlb_lo[(KVM_GUEST_COMMPAGE_ADDR >> PAGE_SHIFT) & 1] = 0;
+
+ if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb_lo[0])
+ >> PAGE_SHIFT) < 0)
+ return -1;
+
+ if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb_lo[1])
+ >> PAGE_SHIFT) < 0)
+ return -1;
+
+ pfn0 = kvm->arch.guest_pmap[
+ mips3_tlbpfn_to_paddr(tlb_lo[0]) >> PAGE_SHIFT];
+ pfn1 = kvm->arch.guest_pmap[
+ mips3_tlbpfn_to_paddr(tlb_lo[1]) >> PAGE_SHIFT];
/* Get attributes from the Guest TLB */
entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) |
((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) |
- (tlb->tlb_lo[0] & ENTRYLO_D) |
- (tlb->tlb_lo[0] & ENTRYLO_V);
+ (tlb_lo[0] & ENTRYLO_D) |
+ (tlb_lo[0] & ENTRYLO_V);
entrylo1 = mips3_paddr_to_tlbpfn(pfn1 << PAGE_SHIFT) |
((_page_cachable_default >> _CACHE_SHIFT) << ENTRYLO_C_SHIFT) |
- (tlb->tlb_lo[1] & ENTRYLO_D) |
- (tlb->tlb_lo[1] & ENTRYLO_V);
+ (tlb_lo[1] & ENTRYLO_D) |
+ (tlb_lo[1] & ENTRYLO_V);
kvm_debug("@ %#lx tlb_lo0: 0x%08lx tlb_lo1: 0x%08lx\n", vcpu->arch.pc,
tlb->tlb_lo[0], tlb->tlb_lo[1]);
--
git-series 0.8.7
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/4] MIPS: KVM: Add missing gfn range check
2016-08-11 10:52 [PATCH 0/4] MIPS: KVM: Fix MMU/TLB management issues James Hogan
2016-08-11 10:58 ` [PATCH 1/4] MIPS: KVM: Fix mapped fault broken commpage handling James Hogan
@ 2016-08-11 10:58 ` James Hogan
2016-08-11 10:58 ` [PATCH 3/4] MIPS: KVM: Fix gfn range check in kseg0 tlb faults James Hogan
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: James Hogan @ 2016-08-11 10:58 UTC (permalink / raw)
To: Paolo Bonzini
Cc: Radim Krčmář, Ralf Baechle, linux-mips, kvm,
stable, James Hogan
kvm_mips_handle_mapped_seg_tlb_fault() calculates the guest frame number
based on the guest TLB EntryLo values, however it is not range checked
to ensure it lies within the guest_pmap. If the physical memory the
guest refers to is out of range then dump the guest TLB and emit an
internal error.
Fixes: 858dd5d45733 ("KVM/MIPS32: MMU/TLB operations for the Guest.")
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Radim Krčmář" <rkrcmar@redhat.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: kvm@vger.kernel.org
Cc: <stable@vger.kernel.org> # 3.10.x-
---
arch/mips/kvm/mmu.c | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/arch/mips/kvm/mmu.c b/arch/mips/kvm/mmu.c
index 96e0b24cfe5c..701c1b64cef8 100644
--- a/arch/mips/kvm/mmu.c
+++ b/arch/mips/kvm/mmu.c
@@ -138,6 +138,7 @@ int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu,
unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
struct kvm *kvm = vcpu->kvm;
kvm_pfn_t pfn0, pfn1;
+ gfn_t gfn0, gfn1;
long tlb_lo[2];
int ret;
@@ -152,18 +153,24 @@ int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu,
VPN2_MASK & (PAGE_MASK << 1)))
tlb_lo[(KVM_GUEST_COMMPAGE_ADDR >> PAGE_SHIFT) & 1] = 0;
- if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb_lo[0])
- >> PAGE_SHIFT) < 0)
+ gfn0 = mips3_tlbpfn_to_paddr(tlb_lo[0]) >> PAGE_SHIFT;
+ gfn1 = mips3_tlbpfn_to_paddr(tlb_lo[1]) >> PAGE_SHIFT;
+ if (gfn0 >= kvm->arch.guest_pmap_npages ||
+ gfn1 >= kvm->arch.guest_pmap_npages) {
+ kvm_err("%s: Invalid gfn: [%#llx, %#llx], EHi: %#lx\n",
+ __func__, gfn0, gfn1, tlb->tlb_hi);
+ kvm_mips_dump_guest_tlbs(vcpu);
+ return -1;
+ }
+
+ if (kvm_mips_map_page(kvm, gfn0) < 0)
return -1;
- if (kvm_mips_map_page(kvm, mips3_tlbpfn_to_paddr(tlb_lo[1])
- >> PAGE_SHIFT) < 0)
+ if (kvm_mips_map_page(kvm, gfn1) < 0)
return -1;
- pfn0 = kvm->arch.guest_pmap[
- mips3_tlbpfn_to_paddr(tlb_lo[0]) >> PAGE_SHIFT];
- pfn1 = kvm->arch.guest_pmap[
- mips3_tlbpfn_to_paddr(tlb_lo[1]) >> PAGE_SHIFT];
+ pfn0 = kvm->arch.guest_pmap[gfn0];
+ pfn1 = kvm->arch.guest_pmap[gfn1];
/* Get attributes from the Guest TLB */
entrylo0 = mips3_paddr_to_tlbpfn(pfn0 << PAGE_SHIFT) |
--
git-series 0.8.7
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/4] MIPS: KVM: Fix gfn range check in kseg0 tlb faults
2016-08-11 10:52 [PATCH 0/4] MIPS: KVM: Fix MMU/TLB management issues James Hogan
2016-08-11 10:58 ` [PATCH 1/4] MIPS: KVM: Fix mapped fault broken commpage handling James Hogan
2016-08-11 10:58 ` [PATCH 2/4] MIPS: KVM: Add missing gfn range check James Hogan
@ 2016-08-11 10:58 ` James Hogan
2016-08-11 10:58 ` [PATCH 4/4] MIPS: KVM: Propagate kseg0/mapped tlb fault errors James Hogan
2016-08-12 12:37 ` [PATCH 0/4] MIPS: KVM: Fix MMU/TLB management issues Radim Krčmář
4 siblings, 0 replies; 6+ messages in thread
From: James Hogan @ 2016-08-11 10:58 UTC (permalink / raw)
To: Paolo Bonzini
Cc: Radim Krčmář, Ralf Baechle, linux-mips, kvm,
stable, James Hogan
Two consecutive gfns are loaded into host TLB, so ensure the range check
isn't off by one if guest_pmap_npages is odd.
Fixes: 858dd5d45733 ("KVM/MIPS32: MMU/TLB operations for the Guest.")
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Radim Krčmář" <rkrcmar@redhat.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: kvm@vger.kernel.org
Cc: <stable@vger.kernel.org> # 3.10.x-
---
arch/mips/kvm/mmu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/mips/kvm/mmu.c b/arch/mips/kvm/mmu.c
index 701c1b64cef8..6a8a21859502 100644
--- a/arch/mips/kvm/mmu.c
+++ b/arch/mips/kvm/mmu.c
@@ -99,7 +99,7 @@ int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr,
}
gfn = (KVM_GUEST_CPHYSADDR(badvaddr) >> PAGE_SHIFT);
- if (gfn >= kvm->arch.guest_pmap_npages) {
+ if ((gfn | 1) >= kvm->arch.guest_pmap_npages) {
kvm_err("%s: Invalid gfn: %#llx, BadVaddr: %#lx\n", __func__,
gfn, badvaddr);
kvm_mips_dump_host_tlbs();
--
git-series 0.8.7
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 4/4] MIPS: KVM: Propagate kseg0/mapped tlb fault errors
2016-08-11 10:52 [PATCH 0/4] MIPS: KVM: Fix MMU/TLB management issues James Hogan
` (2 preceding siblings ...)
2016-08-11 10:58 ` [PATCH 3/4] MIPS: KVM: Fix gfn range check in kseg0 tlb faults James Hogan
@ 2016-08-11 10:58 ` James Hogan
2016-08-12 12:37 ` [PATCH 0/4] MIPS: KVM: Fix MMU/TLB management issues Radim Krčmář
4 siblings, 0 replies; 6+ messages in thread
From: James Hogan @ 2016-08-11 10:58 UTC (permalink / raw)
To: Paolo Bonzini
Cc: Radim Krčmář, Ralf Baechle, linux-mips, kvm,
stable, James Hogan
Propagate errors from kvm_mips_handle_kseg0_tlb_fault() and
kvm_mips_handle_mapped_seg_tlb_fault(), usually triggering an internal
error since they normally indicate the guest accessed bad physical
memory or the commpage in an unexpected way.
Fixes: 858dd5d45733 ("KVM/MIPS32: MMU/TLB operations for the Guest.")
Fixes: e685c689f3a8 ("KVM/MIPS32: Privileged instruction/target branch emulation.")
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: "Radim Krčmář" <rkrcmar@redhat.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: kvm@vger.kernel.org
Cc: <stable@vger.kernel.org> # 3.10.x-
---
arch/mips/kvm/emulate.c | 35 ++++++++++++++++++++++++++---------
arch/mips/kvm/mmu.c | 12 +++++++++---
2 files changed, 35 insertions(+), 12 deletions(-)
diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c
index 6eb52b9c9818..e788515f766b 100644
--- a/arch/mips/kvm/emulate.c
+++ b/arch/mips/kvm/emulate.c
@@ -1642,8 +1642,14 @@ enum emulation_result kvm_mips_emulate_cache(union mips_instruction inst,
preempt_disable();
if (KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG0) {
- if (kvm_mips_host_tlb_lookup(vcpu, va) < 0)
- kvm_mips_handle_kseg0_tlb_fault(va, vcpu);
+ if (kvm_mips_host_tlb_lookup(vcpu, va) < 0 &&
+ kvm_mips_handle_kseg0_tlb_fault(va, vcpu)) {
+ kvm_err("%s: handling mapped kseg0 tlb fault for %lx, vcpu: %p, ASID: %#lx\n",
+ __func__, va, vcpu, read_c0_entryhi());
+ er = EMULATE_FAIL;
+ preempt_enable();
+ goto done;
+ }
} else if ((KVM_GUEST_KSEGX(va) < KVM_GUEST_KSEG0) ||
KVM_GUEST_KSEGX(va) == KVM_GUEST_KSEG23) {
int index;
@@ -1680,12 +1686,18 @@ enum emulation_result kvm_mips_emulate_cache(union mips_instruction inst,
run, vcpu);
preempt_enable();
goto dont_update_pc;
- } else {
- /*
- * We fault an entry from the guest tlb to the
- * shadow host TLB
- */
- kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb);
+ }
+ /*
+ * We fault an entry from the guest tlb to the
+ * shadow host TLB
+ */
+ if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb)) {
+ kvm_err("%s: handling mapped seg tlb fault for %lx, index: %u, vcpu: %p, ASID: %#lx\n",
+ __func__, va, index, vcpu,
+ read_c0_entryhi());
+ er = EMULATE_FAIL;
+ preempt_enable();
+ goto done;
}
}
} else {
@@ -2659,7 +2671,12 @@ enum emulation_result kvm_mips_handle_tlbmiss(u32 cause,
* OK we have a Guest TLB entry, now inject it into the
* shadow host TLB
*/
- kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb);
+ if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu, tlb)) {
+ kvm_err("%s: handling mapped seg tlb fault for %lx, index: %u, vcpu: %p, ASID: %#lx\n",
+ __func__, va, index, vcpu,
+ read_c0_entryhi());
+ er = EMULATE_FAIL;
+ }
}
}
diff --git a/arch/mips/kvm/mmu.c b/arch/mips/kvm/mmu.c
index 6a8a21859502..6cfdcf55572d 100644
--- a/arch/mips/kvm/mmu.c
+++ b/arch/mips/kvm/mmu.c
@@ -368,9 +368,15 @@ u32 kvm_get_inst(u32 *opc, struct kvm_vcpu *vcpu)
local_irq_restore(flags);
return KVM_INVALID_INST;
}
- kvm_mips_handle_mapped_seg_tlb_fault(vcpu,
- &vcpu->arch.
- guest_tlb[index]);
+ if (kvm_mips_handle_mapped_seg_tlb_fault(vcpu,
+ &vcpu->arch.guest_tlb[index])) {
+ kvm_err("%s: handling mapped seg tlb fault failed for %p, index: %u, vcpu: %p, ASID: %#lx\n",
+ __func__, opc, index, vcpu,
+ read_c0_entryhi());
+ kvm_mips_dump_guest_tlbs(vcpu);
+ local_irq_restore(flags);
+ return KVM_INVALID_INST;
+ }
inst = *(opc);
}
local_irq_restore(flags);
--
git-series 0.8.7
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 0/4] MIPS: KVM: Fix MMU/TLB management issues
2016-08-11 10:52 [PATCH 0/4] MIPS: KVM: Fix MMU/TLB management issues James Hogan
` (3 preceding siblings ...)
2016-08-11 10:58 ` [PATCH 4/4] MIPS: KVM: Propagate kseg0/mapped tlb fault errors James Hogan
@ 2016-08-12 12:37 ` Radim Krčmář
4 siblings, 0 replies; 6+ messages in thread
From: Radim Krčmář @ 2016-08-12 12:37 UTC (permalink / raw)
To: James Hogan; +Cc: Paolo Bonzini, Ralf Baechle, linux-mips, kvm, stable
2016-08-11 11:52+0100, James Hogan:
> These patches fix several issues in the management of MIPS KVM TLB
> faults:
>
> 1) kvm_mips_handle_mapped_seg_tlb_fault() misbehaves for virtual address
> zero, which can be hit if the guest creates such a mapping and
> accesses it in a way unexpected for the commpage (e.g. a CACHE
> instruction).
>
> 2) kvm_mips_handle_mapped_seg_tlb_fault() doesn't range check the gfn,
> allowing a high mapping by the guest to overflow the guest_pmap[].
>
> 3) kvm_mips_handle_kseg0_tlb_fault() has an off by one in its gfn range
> check, which could allow an odd sized guest_pmap[] to be overflowed.
>
> 4) some callers of kvm_mips_handle_kseg0_tlb_fault() and
> kvm_mips_handle_mapped_seg_tlb_fault() don't correctly propagate
> errors upwards.
>
> They're all marked for stable but won't apply cleanly before v4.8-rc1
> due to recent changes. I have backports ready though.
Applied, thanks.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2016-08-12 12:37 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-08-11 10:52 [PATCH 0/4] MIPS: KVM: Fix MMU/TLB management issues James Hogan
2016-08-11 10:58 ` [PATCH 1/4] MIPS: KVM: Fix mapped fault broken commpage handling James Hogan
2016-08-11 10:58 ` [PATCH 2/4] MIPS: KVM: Add missing gfn range check James Hogan
2016-08-11 10:58 ` [PATCH 3/4] MIPS: KVM: Fix gfn range check in kseg0 tlb faults James Hogan
2016-08-11 10:58 ` [PATCH 4/4] MIPS: KVM: Propagate kseg0/mapped tlb fault errors James Hogan
2016-08-12 12:37 ` [PATCH 0/4] MIPS: KVM: Fix MMU/TLB management issues Radim Krčmář
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox