]>
Commit | Line | Data |
---|---|---|
d86d85d9 GKH |
1 | From edde99ce05290e50ce0b3495d209e54e6349ab47 Mon Sep 17 00:00:00 2001 |
2 | From: Michael S. Tsirkin <mst@redhat.com> | |
3 | Date: Mon, 25 Oct 2010 03:21:24 +0200 | |
4 | Subject: KVM: Write protect memory after slot swap | |
5 | ||
6 | From: Michael S. Tsirkin <mst@redhat.com> | |
7 | ||
8 | commit edde99ce05290e50ce0b3495d209e54e6349ab47 upstream. | |
9 | ||
10 | I have observed the following bug trigger: | |
11 | ||
12 | 1. userspace calls GET_DIRTY_LOG | |
13 | 2. kvm_mmu_slot_remove_write_access is called and makes a page ro | |
14 | 3. page fault happens and makes the page writeable | |
15 | fault is logged in the bitmap appropriately | |
16 | 4. kvm_vm_ioctl_get_dirty_log swaps slot pointers | |
17 | ||
18 | a lot of time passes | |
19 | ||
20 | 5. guest writes into the page | |
21 | 6. userspace calls GET_DIRTY_LOG | |
22 | ||
23 | At point (5), bitmap is clean and page is writeable, | |
24 | thus, guest modification of memory is not logged | |
25 | and GET_DIRTY_LOG returns an empty bitmap. | |
26 | ||
27 | The rule is that all pages are either dirty in the current bitmap, | |
28 | or write-protected, which is violated here. | |
29 | ||
30 | It seems that just moving kvm_mmu_slot_remove_write_access down | |
31 | to after the slot pointer swap should fix this bug. | |
32 | ||
33 | Signed-off-by: Michael S. Tsirkin <mst@redhat.com> | |
34 | Signed-off-by: Avi Kivity <avi@redhat.com> | |
35 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
36 | ||
37 | --- | |
38 | arch/x86/kvm/x86.c | 8 ++++---- | |
39 | 1 file changed, 4 insertions(+), 4 deletions(-) | |
40 | ||
41 | --- a/arch/x86/kvm/x86.c | |
42 | +++ b/arch/x86/kvm/x86.c | |
43 | @@ -2912,10 +2912,6 @@ int kvm_vm_ioctl_get_dirty_log(struct kv | |
44 | struct kvm_memslots *slots, *old_slots; | |
45 | unsigned long *dirty_bitmap; | |
46 | ||
47 | - spin_lock(&kvm->mmu_lock); | |
48 | - kvm_mmu_slot_remove_write_access(kvm, log->slot); | |
49 | - spin_unlock(&kvm->mmu_lock); | |
50 | - | |
51 | r = -ENOMEM; | |
52 | dirty_bitmap = vmalloc(n); | |
53 | if (!dirty_bitmap) | |
54 | @@ -2937,6 +2933,10 @@ int kvm_vm_ioctl_get_dirty_log(struct kv | |
55 | dirty_bitmap = old_slots->memslots[log->slot].dirty_bitmap; | |
56 | kfree(old_slots); | |
57 | ||
58 | + spin_lock(&kvm->mmu_lock); | |
59 | + kvm_mmu_slot_remove_write_access(kvm, log->slot); | |
60 | + spin_unlock(&kvm->mmu_lock); | |
61 | + | |
62 | r = -EFAULT; | |
63 | if (copy_to_user(log->dirty_bitmap, dirty_bitmap, n)) { | |
64 | vfree(dirty_bitmap); |