* [patch 04/33] KVM: MMU: Fix guest writes to nonpae pde
[not found] ` <20070426165445.GA1898-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
@ 2007-04-26 16:55 ` Greg KH
2007-04-26 16:55 ` [patch 05/33] KVM: MMU: Fix host memory corruption on i386 with >= 4GB ram Greg KH
1 sibling, 0 replies; 2+ messages in thread
From: Greg KH @ 2007-04-26 16:55 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
stable-DgEjT+Ai2ygdnm+yROfE0A
Cc: Theodore Ts'o, Zwane Mwaikambo,
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Justin Forbes,
Chris Wedgwood, Randy Dunlap, Michael Krufky, Chuck Ebbert,
Dave Jones, Chuck Wolber, akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
torvalds-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
alan-qBU/x9rampVanCEyBjwyrvXRex20P6io
[-- Attachment #1: kvm-mmu-fix-guest-writes-to-nonpae-pde.patch --]
[-- Type: text/plain, Size: 3538 bytes --]
-stable review patch. If anyone has any objections, please let us know.
------------------
From: Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
KVM shadow page tables are always in pae mode, regardless of the guest
setting. This means that a guest pde (mapping 4MB of memory) is mapped
to two shadow pdes (mapping 2MB each).
When the guest writes to a pte or pde, we intercept the write and emulate it.
We also remove any shadowed mappings corresponding to the write. Since the
mmu did not account for the doubling in the number of pdes, it removed the
wrong entry, resulting in a mismatch between shadow page tables and guest
page tables, followed shortly by guest memory corruption.
This patch fixes the problem by detecting the special case of writing to
a non-pae pde and adjusting the address and number of shadow pdes zapped
accordingly.
Acked-by: Ingo Molnar <mingo-X9Un+BFzKDI@public.gmane.org>
Signed-off-by: Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
---
drivers/kvm/mmu.c | 47 +++++++++++++++++++++++++++++++++++------------
1 file changed, 35 insertions(+), 12 deletions(-)
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -1093,22 +1093,40 @@ out:
return r;
}
+static void mmu_pre_write_zap_pte(struct kvm_vcpu *vcpu,
+ struct kvm_mmu_page *page,
+ u64 *spte)
+{
+ u64 pte;
+ struct kvm_mmu_page *child;
+
+ pte = *spte;
+ if (is_present_pte(pte)) {
+ if (page->role.level == PT_PAGE_TABLE_LEVEL)
+ rmap_remove(vcpu, spte);
+ else {
+ child = page_header(pte & PT64_BASE_ADDR_MASK);
+ mmu_page_remove_parent_pte(vcpu, child, spte);
+ }
+ }
+ *spte = 0;
+}
+
void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
{
gfn_t gfn = gpa >> PAGE_SHIFT;
struct kvm_mmu_page *page;
- struct kvm_mmu_page *child;
struct hlist_node *node, *n;
struct hlist_head *bucket;
unsigned index;
u64 *spte;
- u64 pte;
unsigned offset = offset_in_page(gpa);
unsigned pte_size;
unsigned page_offset;
unsigned misaligned;
int level;
int flooded = 0;
+ int npte;
pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes);
if (gfn == vcpu->last_pt_write_gfn) {
@@ -1144,22 +1162,27 @@ void kvm_mmu_pre_write(struct kvm_vcpu *
}
page_offset = offset;
level = page->role.level;
+ npte = 1;
if (page->role.glevels == PT32_ROOT_LEVEL) {
- page_offset <<= 1; /* 32->64 */
+ page_offset <<= 1; /* 32->64 */
+ /*
+ * A 32-bit pde maps 4MB while the shadow pdes map
+ * only 2MB. So we need to double the offset again
+ * and zap two pdes instead of one.
+ */
+ if (level == PT32_ROOT_LEVEL) {
+ page_offset &= ~7; /* kill rounding error */
+ page_offset <<= 1;
+ npte = 2;
+ }
page_offset &= ~PAGE_MASK;
}
spte = __va(page->page_hpa);
spte += page_offset / sizeof(*spte);
- pte = *spte;
- if (is_present_pte(pte)) {
- if (level == PT_PAGE_TABLE_LEVEL)
- rmap_remove(vcpu, spte);
- else {
- child = page_header(pte & PT64_BASE_ADDR_MASK);
- mmu_page_remove_parent_pte(vcpu, child, spte);
- }
+ while (npte--) {
+ mmu_pre_write_zap_pte(vcpu, page, spte);
+ ++spte;
}
- *spte = 0;
}
}
--
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
^ permalink raw reply [flat|nested] 2+ messages in thread* [patch 05/33] KVM: MMU: Fix host memory corruption on i386 with >= 4GB ram
[not found] ` <20070426165445.GA1898-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
2007-04-26 16:55 ` [patch 04/33] KVM: MMU: Fix guest writes to nonpae pde Greg KH
@ 2007-04-26 16:55 ` Greg KH
1 sibling, 0 replies; 2+ messages in thread
From: Greg KH @ 2007-04-26 16:55 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
stable-DgEjT+Ai2ygdnm+yROfE0A
Cc: Theodore Ts'o, Zwane Mwaikambo,
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Justin Forbes,
Chris Wedgwood, Randy Dunlap, Michael Krufky, Chuck Ebbert,
Dave Jones, Chuck Wolber, akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
torvalds-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
alan-qBU/x9rampVanCEyBjwyrvXRex20P6io
[-- Attachment #1: kvm-mmu-fix-host-memory-corruption-on-i386-with-4gb-ram.patch --]
[-- Type: text/plain, Size: 1958 bytes --]
-stable review patch. If anyone has any objections, please let us know.
------------------
From: Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
PAGE_MASK is an unsigned long, so using it to mask physical addresses on
i386 (which are 64-bit wide) leads to truncation. This can result in
page->private of unrelated memory pages being modified, with disasterous
results.
Fix by not using PAGE_MASK for physical addresses; instead calculate
the correct value directly from PAGE_SIZE. Also fix a similar BUG_ON().
Acked-by: Ingo Molnar <mingo-X9Un+BFzKDI@public.gmane.org>
Signed-off-by: Avi Kivity <avi-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
Signed-off-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
---
drivers/kvm/mmu.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -131,7 +131,7 @@ static int dbg = 1;
(((address) >> PT32_LEVEL_SHIFT(level)) & ((1 << PT32_LEVEL_BITS) - 1))
-#define PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & PAGE_MASK)
+#define PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1))
#define PT64_DIR_BASE_ADDR_MASK \
(PT64_BASE_ADDR_MASK & ~((1ULL << (PAGE_SHIFT + PT64_LEVEL_BITS)) - 1))
@@ -406,8 +406,8 @@ static void rmap_write_protect(struct kv
spte = desc->shadow_ptes[0];
}
BUG_ON(!spte);
- BUG_ON((*spte & PT64_BASE_ADDR_MASK) !=
- page_to_pfn(page) << PAGE_SHIFT);
+ BUG_ON((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT
+ != page_to_pfn(page));
BUG_ON(!(*spte & PT_PRESENT_MASK));
BUG_ON(!(*spte & PT_WRITABLE_MASK));
rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
--
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
^ permalink raw reply [flat|nested] 2+ messages in thread