From mboxrd@z Thu Jan 1 00:00:00 1970 From: Marcelo Tosatti Subject: KVM: MMU: rmap_write_protect() hugepage iteration bug Date: Sat, 7 Jun 2008 21:27:36 -0300 Message-ID: <20080608002736.GA25582@dmt.cnet> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Cc: kvm-devel To: Avi Kivity Return-path: Received: from mx1.redhat.com ([66.187.233.31]:33386 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755133AbYFHA2I (ORCPT ); Sat, 7 Jun 2008 20:28:08 -0400 Content-Disposition: inline Sender: kvm-owner@vger.kernel.org List-ID: rmap_next() expects the "spte" argument to be NULL whenever there's only one remaining entry in the descriptor. That is, it was not designed to handle changes in the chain while iterating. This bug cripples rmap_write_protect() so that it won't nuke all writable large mappings to a particular gfn. Signed-off-by: Marcelo Tosatti diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index aaccc40..e11ff17 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -632,17 +632,19 @@ static void rmap_write_protect(struct kvm *kvm, u64 gfn) rmapp = gfn_to_rmap(kvm, gfn, 1); spte = rmap_next(kvm, rmapp, NULL); while (spte) { + u64 *next_spte; BUG_ON(!spte); BUG_ON(!(*spte & PT_PRESENT_MASK)); BUG_ON((*spte & (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK)) != (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK)); pgprintk("rmap_write_protect(large): spte %p %llx %lld\n", spte, *spte, gfn); + next_spte = rmap_next(kvm, rmapp, spte); if (is_writeble_pte(*spte)) { rmap_remove(kvm, spte); --kvm->stat.lpages; set_shadow_pte(spte, shadow_trap_nonpresent_pte); write_protected = 1; } - spte = rmap_next(kvm, rmapp, spte); + spte = next_spte; } if (write_protected)