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

Commit 6e84a56c authored by David Matlack's avatar David Matlack Committed by Greg Kroah-Hartman
Browse files

KVM: Prevent module exit until all VMs are freed



commit 5f6de5cbebee925a612856fce6f9182bb3eee0db upstream.

Tie the lifetime the KVM module to the lifetime of each VM via
kvm.users_count. This way anything that grabs a reference to the VM via
kvm_get_kvm() cannot accidentally outlive the KVM module.

Prior to this commit, the lifetime of the KVM module was tied to the
lifetime of /dev/kvm file descriptors, VM file descriptors, and vCPU
file descriptors by their respective file_operations "owner" field.
This approach is insufficient because references grabbed via
kvm_get_kvm() do not prevent closing any of the aforementioned file
descriptors.

This fixes a long standing theoretical bug in KVM that at least affects
async page faults. kvm_setup_async_pf() grabs a reference via
kvm_get_kvm(), and drops it in an asynchronous work callback. Nothing
prevents the VM file descriptor from being closed and the KVM module
from being unloaded before this callback runs.

Fixes: af585b92 ("KVM: Halt vcpu if page it tries to access is swapped out")
Fixes: 3d3aab1b ("KVM: set owner of cpu and vm file operations")
Cc: stable@vger.kernel.org
Suggested-by: default avatarBen Gardon <bgardon@google.com>
[ Based on a patch from Ben implemented for Google's kernel. ]
Signed-off-by: default avatarDavid Matlack <dmatlack@google.com>
Message-Id: <20220303183328.1499189-2-dmatlack@google.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 9e6ab1b7
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -107,6 +107,8 @@ EXPORT_SYMBOL_GPL(kvm_debugfs_dir);
static int kvm_debugfs_num_entries;
static const struct file_operations *stat_fops_per_vm[];

static struct file_operations kvm_chardev_ops;

static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
			   unsigned long arg);
#ifdef CONFIG_KVM_COMPAT
@@ -714,6 +716,16 @@ static struct kvm *kvm_create_vm(unsigned long type)

	preempt_notifier_inc();

	/*
	 * When the fd passed to this ioctl() is opened it pins the module,
	 * but try_module_get() also prevents getting a reference if the module
	 * is in MODULE_STATE_GOING (e.g. if someone ran "rmmod --wait").
	 */
	if (!try_module_get(kvm_chardev_ops.owner)) {
		r = -ENODEV;
		goto out_err;
	}

	return kvm;

out_err:
@@ -798,6 +810,7 @@ static void kvm_destroy_vm(struct kvm *kvm)
	preempt_notifier_dec();
	hardware_disable_all();
	mmdrop(mm);
	module_put(kvm_chardev_ops.owner);
}

void kvm_get_kvm(struct kvm *kvm)