Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 87bf6e7d authored by Takuya Yoshikawa's avatar Takuya Yoshikawa Committed by Avi Kivity
Browse files

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: default avatarTakuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
Signed-off-by: default avatarMarcelo Tosatti <mtosatti@redhat.com>
parent 77662e00
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -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;
+3 −2
Original line number Diff line number Diff line
@@ -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);
	}

+3 −2
Original line number Diff line number Diff line
@@ -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);
+5 −0
Original line number Diff line number Diff line
@@ -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;
+8 −5
Original line number Diff line number Diff line
@@ -648,7 +648,7 @@ int __kvm_set_memory_region(struct kvm *kvm,

	/* 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);
	}
}