public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Andrea Arcangeli <andrea@qumranet.com>
To: Avi Kivity <avi@qumranet.com>
Cc: kvm-devel@lists.sourceforge.net, Marcelo Tosatti <mtosatti@redhat.com>
Subject: Re: [PATCH] KVM: MMU: Fix rmap_remove() race
Date: Wed, 26 Mar 2008 20:22:31 +0100	[thread overview]
Message-ID: <20080326192231.GC11130@v2.random> (raw)
In-Reply-To: <1206543773-26386-1-git-send-email-avi@qumranet.com>

On Wed, Mar 26, 2008 at 05:02:53PM +0200, Avi Kivity wrote:
> Andrea notes that freeing the page before flushing the tlb is a race, as the
> guest can sneak in one last write before the tlb is flushed, writing to a
> page that may belong to someone else.
> 
> Fix be reversing the order of freeing and flushing the tlb.  Since the tlb
> flush is expensive, queue the pages to be freed so we need to flush just once.

Problem is the *spte = nonpresent, must now happen _before_
rmap_remove for this race to be fixed. So we either remove the
is_rmap_pte from the top of rmap_remove and we reorder all the
callers, or we apply this.

I'm not sure anymore the mmu notifiers are enough to fix this, because
what happens if invalidate_page runs after rmap_remove is returned
(the spte isn't visible anymore by the rmap code and in turn by
invalidate_page) but before the set_shadow_pte(nonpresent) runs.

Index: arch/x86/kvm/mmu.c
--- arch/x86/kvm/mmu.c.~1~	2008-03-26 16:55:14.000000000 +0100
+++ arch/x86/kvm/mmu.c	2008-03-26 19:57:53.000000000 +0100
@@ -582,7 +582,7 @@ static void kvm_release_page_clean_defer
 	kvm_release_page_deferred(kvm, page, true);
 }
 
-static void rmap_remove(struct kvm *kvm, u64 *spte)
+static void rmap_remove(struct kvm *kvm, u64 *sptep)
 {
 	struct kvm_rmap_desc *desc;
 	struct kvm_rmap_desc *prev_desc;
@@ -590,35 +590,37 @@ static void rmap_remove(struct kvm *kvm,
 	struct page *page;
 	unsigned long *rmapp;
 	int i;
+	u64 spte = *sptep;
 
-	if (!is_rmap_pte(*spte))
+	if (!is_rmap_pte(spte))
 		return;
-	sp = page_header(__pa(spte));
-	page = spte_to_page(*spte);
+	sp = page_header(__pa(sptep));
+	page = spte_to_page(spte);
 	mark_page_accessed(page);
-	if (is_writeble_pte(*spte))
+	set_shadow_pte(sptep, shadow_trap_nonpresent_pte);
+	if (is_writeble_pte(spte))
 		kvm_release_page_dirty_deferred(kvm, page);
 	else
 		kvm_release_page_clean_deferred(kvm, page);
-	rmapp = gfn_to_rmap(kvm, sp->gfns[spte - sp->spt], is_large_pte(*spte));
+	rmapp = gfn_to_rmap(kvm, sp->gfns[sptep - sp->spt], is_large_pte(spte));
 	if (!*rmapp) {
-		printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte);
+		printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", sptep, spte);
 		BUG();
 	} else if (!(*rmapp & 1)) {
-		rmap_printk("rmap_remove:  %p %llx 1->0\n", spte, *spte);
-		if ((u64 *)*rmapp != spte) {
+		rmap_printk("rmap_remove:  %p %llx 1->0\n", sptep, spte);
+		if ((u64 *)*rmapp != sptep) {
 			printk(KERN_ERR "rmap_remove:  %p %llx 1->BUG\n",
-			       spte, *spte);
+			       sptep, spte);
 			BUG();
 		}
 		*rmapp = 0;
 	} else {
-		rmap_printk("rmap_remove:  %p %llx many->many\n", spte, *spte);
+		rmap_printk("rmap_remove:  %p %llx many->many\n", sptep, spte);
 		desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul);
 		prev_desc = NULL;
 		while (desc) {
 			for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i)
-				if (desc->shadow_ptes[i] == spte) {
+				if (desc->shadow_ptes[i] == sptep) {
 					rmap_desc_remove_entry(rmapp,
 							       desc, i,
 							       prev_desc);


-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace

  parent reply	other threads:[~2008-03-26 19:22 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-03-26 15:02 [PATCH] KVM: MMU: Fix rmap_remove() race Avi Kivity
2008-03-26 15:15 ` Avi Kivity
2008-03-26 17:51 ` Marcelo Tosatti
2008-03-26 18:12   ` Andrea Arcangeli
2008-03-26 19:01     ` Marcelo Tosatti
2008-03-27  8:01     ` Avi Kivity
2008-03-26 19:22 ` Andrea Arcangeli [this message]
2008-03-26 19:27   ` Andrea Arcangeli
2008-03-27  8:06     ` Avi Kivity
2008-03-27  8:11     ` Avi Kivity
2008-03-27 13:52       ` Andrea Arcangeli
2008-03-27 13:56         ` Avi Kivity
2008-03-27 14:26           ` Andrea Arcangeli
2008-03-27 14:35             ` Avi Kivity
2008-03-27 14:50               ` Andrea Arcangeli
2008-03-27 14:56                 ` Avi Kivity
2008-03-28 14:01                 ` Andrea Arcangeli
2008-03-28 20:07                   ` Andrea Arcangeli
2008-03-31  6:35                   ` Avi Kivity
2008-03-31  9:25                     ` Andrea Arcangeli
2008-03-27 15:26 ` Andi Kleen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080326192231.GC11130@v2.random \
    --to=andrea@qumranet.com \
    --cc=avi@qumranet.com \
    --cc=kvm-devel@lists.sourceforge.net \
    --cc=mtosatti@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox