diff options
author | Michael S. Tsirkin <mst@redhat.com> | 2010-10-24 21:21:24 -0400 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2010-11-05 12:42:25 -0400 |
commit | edde99ce05290e50ce0b3495d209e54e6349ab47 (patch) | |
tree | efb966684a2999613ab81e5d30a9118acdb9fbef /arch/x86/kvm | |
parent | ff8b16d7e15a8ba2a6086645614a483e048e3fbf (diff) |
KVM: Write protect memory after slot swap
I have observed the following bug trigger:
1. userspace calls GET_DIRTY_LOG
2. kvm_mmu_slot_remove_write_access is called and makes a page ro
3. page fault happens and makes the page writeable
fault is logged in the bitmap appropriately
4. kvm_vm_ioctl_get_dirty_log swaps slot pointers
a lot of time passes
5. guest writes into the page
6. userspace calls GET_DIRTY_LOG
At point (5), bitmap is clean and page is writeable,
thus, guest modification of memory is not logged
and GET_DIRTY_LOG returns an empty bitmap.
The rule is that all pages are either dirty in the current bitmap,
or write-protected, which is violated here.
It seems that just moving kvm_mmu_slot_remove_write_access down
to after the slot pointer swap should fix this bug.
KVM-Stable-Tag.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r-- | arch/x86/kvm/x86.c | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2288ad829b32..b0818f672064 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -3169,10 +3169,6 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, | |||
3169 | struct kvm_memslots *slots, *old_slots; | 3169 | struct kvm_memslots *slots, *old_slots; |
3170 | unsigned long *dirty_bitmap; | 3170 | unsigned long *dirty_bitmap; |
3171 | 3171 | ||
3172 | spin_lock(&kvm->mmu_lock); | ||
3173 | kvm_mmu_slot_remove_write_access(kvm, log->slot); | ||
3174 | spin_unlock(&kvm->mmu_lock); | ||
3175 | |||
3176 | r = -ENOMEM; | 3172 | r = -ENOMEM; |
3177 | dirty_bitmap = vmalloc(n); | 3173 | dirty_bitmap = vmalloc(n); |
3178 | if (!dirty_bitmap) | 3174 | if (!dirty_bitmap) |
@@ -3194,6 +3190,10 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, | |||
3194 | dirty_bitmap = old_slots->memslots[log->slot].dirty_bitmap; | 3190 | dirty_bitmap = old_slots->memslots[log->slot].dirty_bitmap; |
3195 | kfree(old_slots); | 3191 | kfree(old_slots); |
3196 | 3192 | ||
3193 | spin_lock(&kvm->mmu_lock); | ||
3194 | kvm_mmu_slot_remove_write_access(kvm, log->slot); | ||
3195 | spin_unlock(&kvm->mmu_lock); | ||
3196 | |||
3197 | r = -EFAULT; | 3197 | r = -EFAULT; |
3198 | if (copy_to_user(log->dirty_bitmap, dirty_bitmap, n)) { | 3198 | if (copy_to_user(log->dirty_bitmap, dirty_bitmap, n)) { |
3199 | vfree(dirty_bitmap); | 3199 | vfree(dirty_bitmap); |