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
next prev 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