diff mbox series

[RFC,v6,11/92] kvm: introspection: add vCPU related data

Message ID 20190809160047.8319-12-alazar@bitdefender.com
State New, archived
Headers show
Series VM introspection | expand

Commit Message

Adalbert Lazăr Aug. 9, 2019, 3:59 p.m. UTC
From: Mircea Cîrjaliu <mcirjaliu@bitdefender.com>

An opaque pointer is added to struct kvm_vcpu, pointing to its
coresponding introspection structure, allocated (a) when the introspection
socket is connected or (b) when the vCPU is hotpluged and deallocated
when the introspection socket is disconnected.

Signed-off-by: Mircea Cîrjaliu <mcirjaliu@bitdefender.com>
Signed-off-by: Adalbert Lazăr <alazar@bitdefender.com>
---
 include/linux/kvm_host.h |  1 +
 include/linux/kvmi.h     |  4 +++
 virt/kvm/kvm_main.c      |  8 +++++
 virt/kvm/kvmi.c          | 73 +++++++++++++++++++++++++++++++++++++++-
 virt/kvm/kvmi_int.h      |  5 +++
 5 files changed, 90 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 582b0187f5a4..1ec04384fad3 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -275,6 +275,7 @@  struct kvm_vcpu {
 	bool preempted;
 	struct kvm_vcpu_arch arch;
 	struct dentry *debugfs_dentry;
+	void *kvmi;
 };
 
 static inline int kvm_vcpu_exiting_guest_mode(struct kvm_vcpu *vcpu)
diff --git a/include/linux/kvmi.h b/include/linux/kvmi.h
index 4ca9280e4419..e8d25d7da751 100644
--- a/include/linux/kvmi.h
+++ b/include/linux/kvmi.h
@@ -14,6 +14,8 @@  int kvmi_ioctl_hook(struct kvm *kvm, void __user *argp);
 int kvmi_ioctl_command(struct kvm *kvm, void __user *argp);
 int kvmi_ioctl_event(struct kvm *kvm, void __user *argp);
 int kvmi_ioctl_unhook(struct kvm *kvm, bool force_reset);
+int kvmi_vcpu_init(struct kvm_vcpu *vcpu);
+void kvmi_vcpu_uninit(struct kvm_vcpu *vcpu);
 
 #else
 
@@ -21,6 +23,8 @@  static inline int kvmi_init(void) { return 0; }
 static inline void kvmi_uninit(void) { }
 static inline void kvmi_create_vm(struct kvm *kvm) { }
 static inline void kvmi_destroy_vm(struct kvm *kvm) { }
+static inline int kvmi_vcpu_init(struct kvm_vcpu *vcpu) { return 0; }
+static inline void kvmi_vcpu_uninit(struct kvm_vcpu *vcpu) { }
 
 #endif /* CONFIG_KVM_INTROSPECTION */
 
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 8399b826f2d2..94f15f393e37 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -316,6 +316,13 @@  int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
 	r = kvm_arch_vcpu_init(vcpu);
 	if (r < 0)
 		goto fail_free_run;
+
+	r = kvmi_vcpu_init(vcpu);
+	if (r < 0) {
+		kvm_arch_vcpu_uninit(vcpu);
+		goto fail_free_run;
+	}
+
 	return 0;
 
 fail_free_run:
@@ -333,6 +340,7 @@  void kvm_vcpu_uninit(struct kvm_vcpu *vcpu)
 	 * descriptors are already gone.
 	 */
 	put_pid(rcu_dereference_protected(vcpu->pid, 1));
+	kvmi_vcpu_uninit(vcpu);
 	kvm_arch_vcpu_uninit(vcpu);
 	free_page((unsigned long)vcpu->run);
 }
diff --git a/virt/kvm/kvmi.c b/virt/kvm/kvmi.c
index 961e6cc13fb6..860574039221 100644
--- a/virt/kvm/kvmi.c
+++ b/virt/kvm/kvmi.c
@@ -80,6 +80,19 @@  static bool alloc_kvmi(struct kvm *kvm, const struct kvm_introspection *qemu)
 	return true;
 }
 
+static bool alloc_ivcpu(struct kvm_vcpu *vcpu)
+{
+	struct kvmi_vcpu *ivcpu;
+
+	ivcpu = kzalloc(sizeof(*ivcpu), GFP_KERNEL);
+	if (!ivcpu)
+		return false;
+
+	vcpu->kvmi = ivcpu;
+
+	return true;
+}
+
 struct kvmi * __must_check kvmi_get(struct kvm *kvm)
 {
 	if (refcount_inc_not_zero(&kvm->kvmi_ref))
@@ -90,8 +103,16 @@  struct kvmi * __must_check kvmi_get(struct kvm *kvm)
 
 static void kvmi_destroy(struct kvm *kvm)
 {
+	struct kvm_vcpu *vcpu;
+	int i;
+
 	kfree(kvm->kvmi);
 	kvm->kvmi = NULL;
+
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		kfree(vcpu->kvmi);
+		vcpu->kvmi = NULL;
+	}
 }
 
 static void kvmi_release(struct kvm *kvm)
@@ -109,6 +130,48 @@  void kvmi_put(struct kvm *kvm)
 		kvmi_release(kvm);
 }
 
+/*
+ * VCPU hotplug - this function will likely be called before VCPU will start
+ * executing code
+ */
+int kvmi_vcpu_init(struct kvm_vcpu *vcpu)
+{
+	struct kvmi *ikvm;
+	int ret = 0;
+
+	ikvm = kvmi_get(vcpu->kvm);
+	if (!ikvm)
+		return 0;
+
+	if (!alloc_ivcpu(vcpu)) {
+		kvmi_err(ikvm, "Unable to alloc ivcpu for vcpu_id %u\n",
+			 vcpu->vcpu_id);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+out:
+	kvmi_put(vcpu->kvm);
+
+	return ret;
+}
+
+/*
+ * VCPU hotplug - this function will likely be called after VCPU will stop
+ * executing code
+ */
+void kvmi_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+	/*
+	 * Under certain circumstances (errors in creating the VCPU, hotplug?)
+	 * this function may be reached with the KVMI member still allocated.
+	 * This VCPU won't be reachable by the introspection engine, so no
+	 * protection is necessary when de-allocating.
+	 */
+	kfree(vcpu->kvmi);
+	vcpu->kvmi = NULL;
+}
+
 static void kvmi_end_introspection(struct kvmi *ikvm)
 {
 	struct kvm *kvm = ikvm->kvm;
@@ -142,8 +205,9 @@  static int kvmi_recv(void *arg)
 
 int kvmi_hook(struct kvm *kvm, const struct kvm_introspection *qemu)
 {
+	struct kvm_vcpu *vcpu;
 	struct kvmi *ikvm;
-	int err = 0;
+	int i, err = 0;
 
 	/* wait for the previous introspection to finish */
 	err = wait_for_completion_killable(&kvm->kvmi_completed);
@@ -159,6 +223,13 @@  int kvmi_hook(struct kvm *kvm, const struct kvm_introspection *qemu)
 	}
 	ikvm = IKVM(kvm);
 
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		if (!alloc_ivcpu(vcpu)) {
+			err = -ENOMEM;
+			goto err_alloc;
+		}
+	}
+
 	/* interact with other kernel components after structure allocation */
 	if (!kvmi_sock_get(ikvm, qemu->fd)) {
 		err = -EINVAL;
diff --git a/virt/kvm/kvmi_int.h b/virt/kvm/kvmi_int.h
index 84ba43bd9a9d..8739a3435893 100644
--- a/virt/kvm/kvmi_int.h
+++ b/virt/kvm/kvmi_int.h
@@ -23,6 +23,8 @@ 
 #define kvmi_err(ikvm, fmt, ...) \
 	kvm_info("%pU ERROR: " fmt, &ikvm->uuid, ## __VA_ARGS__)
 
+#define IVCPU(vcpu) ((struct kvmi_vcpu *)((vcpu)->kvmi))
+
 #define KVMI_MSG_SIZE_ALLOC (sizeof(struct kvmi_msg_hdr) + KVMI_MSG_SIZE)
 
 #define KVMI_KNOWN_VCPU_EVENTS ( \
@@ -73,6 +75,9 @@ 
 
 #define KVMI_NUM_COMMANDS KVMI_NEXT_AVAILABLE_COMMAND
 
+struct kvmi_vcpu {
+};
+
 #define IKVM(kvm) ((struct kvmi *)((kvm)->kvmi))
 
 struct kvmi {