| From mtosatti@redhat.com Fri Oct 29 15:19:23 2010 |
| From: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> |
| Date: Thu, 28 Oct 2010 16:48:10 -0200 |
| Subject: KVM: MMU: fix direct sps access corrupted |
| To: greg@kroah.com |
| Cc: avi@redhat.com, mtosatti@redhat.com, stable@kernel.org, Xiao Guangrong <xiaoguangrong@cn.fujitsu.com>, Greg Kroah-Hartman <gregkh@suse.de> |
| Message-ID: <20101028185027.102565890@amt.cnet> |
| Content-Disposition: inline; filename=0002-KVM-MMU-fix-direct-sp-s-access-corrupted.patch |
| |
| From: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> |
| |
| commit 9e7b0e7fba45ca3c6357aeb7091ebc281f1de365 upstream. |
| |
| If the mapping is writable but the dirty flag is not set, we will find |
| the read-only direct sp and setup the mapping, then if the write #PF |
| occur, we will mark this mapping writable in the read-only direct sp, |
| now, other real read-only mapping will happily write it without #PF. |
| |
| It may hurt guest's COW |
| |
| Fixed by re-install the mapping when write #PF occur. |
| |
| Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> |
| Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| arch/x86/kvm/paging_tmpl.h | 28 ++++++++++++++++++++++++++-- |
| 1 file changed, 26 insertions(+), 2 deletions(-) |
| |
| --- a/arch/x86/kvm/paging_tmpl.h |
| +++ b/arch/x86/kvm/paging_tmpl.h |
| @@ -318,8 +318,32 @@ static u64 *FNAME(fetch)(struct kvm_vcpu |
| break; |
| } |
| |
| - if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep)) |
| - continue; |
| + if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep)) { |
| + struct kvm_mmu_page *child; |
| + unsigned direct_access; |
| + |
| + if (level != gw->level) |
| + continue; |
| + |
| + /* |
| + * For the direct sp, if the guest pte's dirty bit |
| + * changed form clean to dirty, it will corrupt the |
| + * sp's access: allow writable in the read-only sp, |
| + * so we should update the spte at this point to get |
| + * a new sp with the correct access. |
| + */ |
| + direct_access = gw->pt_access & gw->pte_access; |
| + if (!is_dirty_gpte(gw->ptes[gw->level - 1])) |
| + direct_access &= ~ACC_WRITE_MASK; |
| + |
| + child = page_header(*sptep & PT64_BASE_ADDR_MASK); |
| + if (child->role.access == direct_access) |
| + continue; |
| + |
| + mmu_page_remove_parent_pte(child, sptep); |
| + __set_spte(sptep, shadow_trap_nonpresent_pte); |
| + kvm_flush_remote_tlbs(vcpu->kvm); |
| + } |
| |
| if (is_large_pte(*sptep)) { |
| rmap_remove(vcpu->kvm, sptep); |