Commit 4e4f38f8 authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

Merge tag 'kvm-memslots-6.14' of https://github.com/kvm-x86/linux into HEAD

KVM kvm_set_memory_region() cleanups and hardening for 6.14:

 - Add proper lockdep assertions when setting memory regions.

 - Add a dedicated API for setting KVM-internal memory regions.

 - Explicitly disallow all flags for KVM-internal memory regions.
parents 5cf32aff 0cc3cb21
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -12800,7 +12800,8 @@ void __user * __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa,
	struct kvm_memslots *slots = kvm_memslots(kvm);
	struct kvm_memory_slot *slot;

	/* Called with kvm->slots_lock held.  */
	lockdep_assert_held(&kvm->slots_lock);

	if (WARN_ON(id >= KVM_MEM_SLOTS_NUM))
		return ERR_PTR_USR(-EINVAL);

@@ -12833,7 +12834,7 @@ void __user * __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa,
		m.guest_phys_addr = gpa;
		m.userspace_addr = hva;
		m.memory_size = size;
		r = __kvm_set_memory_region(kvm, &m);
		r = kvm_set_internal_memslot(kvm, &m);
		if (r < 0)
			return ERR_PTR_USR(r);
	}
@@ -12934,7 +12935,7 @@ static int kvm_alloc_memslot_metadata(struct kvm *kvm,

	/*
	 * Clear out the previous array pointers for the KVM_MR_MOVE case.  The
	 * old arrays will be freed by __kvm_set_memory_region() if installing
	 * old arrays will be freed by kvm_set_memory_region() if installing
	 * the new memslot is successful.
	 */
	memset(&slot->arch, 0, sizeof(slot->arch));
+3 −5
Original line number Diff line number Diff line
@@ -1183,7 +1183,7 @@ struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn
 *   -- just change its flags
 *
 * Since flags can be changed by some of these operations, the following
 * differentiation is the best we can do for __kvm_set_memory_region():
 * differentiation is the best we can do for kvm_set_memory_region():
 */
enum kvm_mr_change {
	KVM_MR_CREATE,
@@ -1192,9 +1192,7 @@ enum kvm_mr_change {
	KVM_MR_FLAGS_ONLY,
};

int kvm_set_memory_region(struct kvm *kvm,
			  const struct kvm_userspace_memory_region2 *mem);
int __kvm_set_memory_region(struct kvm *kvm,
int kvm_set_internal_memslot(struct kvm *kvm,
			     const struct kvm_userspace_memory_region2 *mem);
void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot);
void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen);
+14 −19
Original line number Diff line number Diff line
@@ -1926,15 +1926,7 @@ static bool kvm_check_memslot_overlap(struct kvm_memslots *slots, int id,
	return false;
}

/*
 * Allocate some memory and give it an address in the guest physical address
 * space.
 *
 * Discontiguous memory is allowed, mostly for framebuffers.
 *
 * Must be called holding kvm->slots_lock for write.
 */
int __kvm_set_memory_region(struct kvm *kvm,
static int kvm_set_memory_region(struct kvm *kvm,
				 const struct kvm_userspace_memory_region2 *mem)
{
	struct kvm_memory_slot *old, *new;
@@ -1945,6 +1937,8 @@ int __kvm_set_memory_region(struct kvm *kvm,
	int as_id, id;
	int r;

	lockdep_assert_held(&kvm->slots_lock);

	r = check_memory_region_flags(kvm, mem);
	if (r)
		return r;
@@ -2056,19 +2050,19 @@ int __kvm_set_memory_region(struct kvm *kvm,
	kfree(new);
	return r;
}
EXPORT_SYMBOL_GPL(__kvm_set_memory_region);

int kvm_set_memory_region(struct kvm *kvm,
int kvm_set_internal_memslot(struct kvm *kvm,
			     const struct kvm_userspace_memory_region2 *mem)
{
	int r;
	if (WARN_ON_ONCE(mem->slot < KVM_USER_MEM_SLOTS))
		return -EINVAL;

	mutex_lock(&kvm->slots_lock);
	r = __kvm_set_memory_region(kvm, mem);
	mutex_unlock(&kvm->slots_lock);
	return r;
	if (WARN_ON_ONCE(mem->flags))
		return -EINVAL;

	return kvm_set_memory_region(kvm, mem);
}
EXPORT_SYMBOL_GPL(kvm_set_memory_region);
EXPORT_SYMBOL_GPL(kvm_set_internal_memslot);

static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
					  struct kvm_userspace_memory_region2 *mem)
@@ -2076,6 +2070,7 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
	if ((u16)mem->slot >= KVM_USER_MEM_SLOTS)
		return -EINVAL;

	guard(mutex)(&kvm->slots_lock);
	return kvm_set_memory_region(kvm, mem);
}