KVM: fix the handling of dirty bitmaps to avoid overflows
Int is not long enough to store the size of a dirty bitmap. This patch fixes this problem with the introduction of a wrapper function to calculate the sizes of dirty bitmaps. Note: in mark_page_dirty(), we have to consider the fact that __set_bit() takes the offset as int, not long. Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
This commit is contained in:
parent
77662e0028
commit
87bf6e7de1
@ -1802,7 +1802,8 @@ static int kvm_ia64_sync_dirty_log(struct kvm *kvm,
|
||||
{
|
||||
struct kvm_memory_slot *memslot;
|
||||
int r, i;
|
||||
long n, base;
|
||||
long base;
|
||||
unsigned long n;
|
||||
unsigned long *dirty_bitmap = (unsigned long *)(kvm->arch.vm_base +
|
||||
offsetof(struct kvm_vm_data, kvm_mem_dirty_log));
|
||||
|
||||
@ -1815,7 +1816,7 @@ static int kvm_ia64_sync_dirty_log(struct kvm *kvm,
|
||||
if (!memslot->dirty_bitmap)
|
||||
goto out;
|
||||
|
||||
n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
|
||||
n = kvm_dirty_bitmap_bytes(memslot);
|
||||
base = memslot->base_gfn / BITS_PER_LONG;
|
||||
|
||||
for (i = 0; i < n/sizeof(long); ++i) {
|
||||
@ -1831,7 +1832,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
|
||||
struct kvm_dirty_log *log)
|
||||
{
|
||||
int r;
|
||||
int n;
|
||||
unsigned long n;
|
||||
struct kvm_memory_slot *memslot;
|
||||
int is_dirty = 0;
|
||||
|
||||
@ -1850,7 +1851,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
|
||||
if (is_dirty) {
|
||||
kvm_flush_remote_tlbs(kvm);
|
||||
memslot = &kvm->memslots->memslots[log->slot];
|
||||
n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
|
||||
n = kvm_dirty_bitmap_bytes(memslot);
|
||||
memset(memslot->dirty_bitmap, 0, n);
|
||||
}
|
||||
r = 0;
|
||||
|
@ -1004,7 +1004,8 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
|
||||
struct kvm_vcpu *vcpu;
|
||||
ulong ga, ga_end;
|
||||
int is_dirty = 0;
|
||||
int r, n;
|
||||
int r;
|
||||
unsigned long n;
|
||||
|
||||
mutex_lock(&kvm->slots_lock);
|
||||
|
||||
@ -1022,7 +1023,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
|
||||
kvm_for_each_vcpu(n, vcpu, kvm)
|
||||
kvmppc_mmu_pte_pflush(vcpu, ga, ga_end);
|
||||
|
||||
n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
|
||||
n = kvm_dirty_bitmap_bytes(memslot);
|
||||
memset(memslot->dirty_bitmap, 0, n);
|
||||
}
|
||||
|
||||
|
@ -2612,8 +2612,9 @@ static int kvm_vm_ioctl_reinject(struct kvm *kvm,
|
||||
int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
|
||||
struct kvm_dirty_log *log)
|
||||
{
|
||||
int r, n, i;
|
||||
int r, i;
|
||||
struct kvm_memory_slot *memslot;
|
||||
unsigned long n;
|
||||
unsigned long is_dirty = 0;
|
||||
unsigned long *dirty_bitmap = NULL;
|
||||
|
||||
@ -2628,7 +2629,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
|
||||
if (!memslot->dirty_bitmap)
|
||||
goto out;
|
||||
|
||||
n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
|
||||
n = kvm_dirty_bitmap_bytes(memslot);
|
||||
|
||||
r = -ENOMEM;
|
||||
dirty_bitmap = vmalloc(n);
|
||||
|
@ -119,6 +119,11 @@ struct kvm_memory_slot {
|
||||
int user_alloc;
|
||||
};
|
||||
|
||||
static inline unsigned long kvm_dirty_bitmap_bytes(struct kvm_memory_slot *memslot)
|
||||
{
|
||||
return ALIGN(memslot->npages, BITS_PER_LONG) / 8;
|
||||
}
|
||||
|
||||
struct kvm_kernel_irq_routing_entry {
|
||||
u32 gsi;
|
||||
u32 type;
|
||||
|
@ -648,7 +648,7 @@ skip_lpage:
|
||||
|
||||
/* Allocate page dirty bitmap if needed */
|
||||
if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) {
|
||||
unsigned dirty_bytes = ALIGN(npages, BITS_PER_LONG) / 8;
|
||||
unsigned long dirty_bytes = kvm_dirty_bitmap_bytes(&new);
|
||||
|
||||
new.dirty_bitmap = vmalloc(dirty_bytes);
|
||||
if (!new.dirty_bitmap)
|
||||
@ -768,7 +768,7 @@ int kvm_get_dirty_log(struct kvm *kvm,
|
||||
{
|
||||
struct kvm_memory_slot *memslot;
|
||||
int r, i;
|
||||
int n;
|
||||
unsigned long n;
|
||||
unsigned long any = 0;
|
||||
|
||||
r = -EINVAL;
|
||||
@ -780,7 +780,7 @@ int kvm_get_dirty_log(struct kvm *kvm,
|
||||
if (!memslot->dirty_bitmap)
|
||||
goto out;
|
||||
|
||||
n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
|
||||
n = kvm_dirty_bitmap_bytes(memslot);
|
||||
|
||||
for (i = 0; !any && i < n/sizeof(long); ++i)
|
||||
any = memslot->dirty_bitmap[i];
|
||||
@ -1186,10 +1186,13 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
|
||||
memslot = gfn_to_memslot_unaliased(kvm, gfn);
|
||||
if (memslot && memslot->dirty_bitmap) {
|
||||
unsigned long rel_gfn = gfn - memslot->base_gfn;
|
||||
unsigned long *p = memslot->dirty_bitmap +
|
||||
rel_gfn / BITS_PER_LONG;
|
||||
int offset = rel_gfn % BITS_PER_LONG;
|
||||
|
||||
/* avoid RMW */
|
||||
if (!generic_test_le_bit(rel_gfn, memslot->dirty_bitmap))
|
||||
generic___set_le_bit(rel_gfn, memslot->dirty_bitmap);
|
||||
if (!generic_test_le_bit(offset, p))
|
||||
generic___set_le_bit(offset, p);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user