KVM: MMU: Fix inherited permissions for emulated guest pte updates
When we emulate a guest pte write, we fail to apply the correct inherited
permissions from the parent ptes. Now that we store inherited permissions
in the shadow page, we can use that to update the pte permissions correctly.
Signed-off-by: Avi Kivity <avi@qumranet.com>
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 0d3555b..ceefb442 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -55,7 +55,7 @@
* bits 4:7 - page table level for this shadow (1-4)
* bits 8:9 - page table quadrant for 2-level guests
* bit 16 - "metaphysical" - gfn is not a real page (huge page/real mode)
- * bits 17:19 - "access" - the user, writable, and nx bits of a huge page pde
+ * bits 17:19 - common access permissions for all ptes in this shadow page
*/
union kvm_mmu_page_role {
unsigned word;
@@ -65,7 +65,7 @@
unsigned quadrant : 2;
unsigned pad_for_nice_hex_output : 6;
unsigned metaphysical : 1;
- unsigned hugepage_access : 3;
+ unsigned access : 3;
};
};
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index f8a2137..cace1e4 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -680,7 +680,7 @@
gva_t gaddr,
unsigned level,
int metaphysical,
- unsigned hugepage_access,
+ unsigned access,
u64 *parent_pte)
{
union kvm_mmu_page_role role;
@@ -694,7 +694,7 @@
role.glevels = vcpu->mmu.root_level;
role.level = level;
role.metaphysical = metaphysical;
- role.hugepage_access = hugepage_access;
+ role.access = access;
if (vcpu->mmu.root_level <= PT32_ROOT_LEVEL) {
quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level));
quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1;
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index 1fc4f9b..211fef8 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -327,6 +327,7 @@
int offset_in_pte)
{
pt_element_t gpte;
+ unsigned pte_access;
gpte = *(const pt_element_t *)pte;
if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) {
@@ -337,7 +338,8 @@
if (bytes < sizeof(pt_element_t))
return;
pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte);
- FNAME(set_pte)(vcpu, gpte, spte, ACC_ALL, ACC_ALL,
+ pte_access = page->role.access & FNAME(gpte_access)(vcpu, gpte);
+ FNAME(set_pte)(vcpu, gpte, spte, page->role.access, pte_access,
0, 0, NULL, NULL, gpte_to_gfn(gpte));
}