@@ -4946,6 +4946,34 @@ the event is disallowed.
Unless set to -1 (meaning all events), id must be a event ID
(e.g. KVMI_VM_EVENT_UNHOOK, KVMI_VCPU_EVENT_CR, etc.)
+4.131 KVM_INTROSPECTION_PREUNHOOK
+---------------------------------
+
+:Capability: KVM_CAP_INTROSPECTION
+:Architectures: x86
+:Type: vm ioctl
+:Parameters: none
+:Returns: 0 on success, a negative value on error
+
+Errors:
+
+ ====== ============================================================
+ EFAULT the VM is not introspected yet (use KVM_INTROSPECTION_HOOK)
+ ENOENT the socket (passed with KVM_INTROSPECTION_HOOK) had an error
+ ENOENT the introspection tool didn't subscribed
+ to this type of introspection event (unhook)
+ ====== ============================================================
+
+This ioctl is used to inform that the current VM is
+paused/suspended/migrated/etc.
+
+KVM should send an 'unhook' introspection event to the introspection tool.
+
+If this ioctl is successful, the userspace should give the
+introspection tool a chance to unhook the VM and then it should use
+KVM_INTROSPECTION_UNHOOK to make sure all the introspection structures
+are freed.
+
5. The kvm_run structure
========================
@@ -183,9 +183,10 @@ becomes necessary to remove them before the guest is suspended, moved
(migrated) or a snapshot with memory is created.
The actions are normally performed by the device manager. In the case
-of QEMU, it will use another ioctl to notify the introspection tool and
-wait for a limited amount of time (a few seconds) for a confirmation that
-is OK to proceed (the introspection tool will close the connection).
+of QEMU, it will use the *KVM_INTROSPECTION_PREUNHOOK* ioctl to trigger
+the *KVMI_VM_EVENT_UNHOOK* event and wait for a limited amount of time (a
+few seconds) for a confirmation that is OK to proceed. The introspection
+tool will close the connection to signal this.
Live migrations
---------------
@@ -32,6 +32,7 @@ int kvmi_ioctl_command(struct kvm *kvm,
const struct kvm_introspection_feature *feat);
int kvmi_ioctl_event(struct kvm *kvm,
const struct kvm_introspection_feature *feat);
+int kvmi_ioctl_preunhook(struct kvm *kvm);
#else
@@ -1661,6 +1661,8 @@ struct kvm_introspection_feature {
#define KVM_INTROSPECTION_COMMAND _IOW(KVMIO, 0xca, struct kvm_introspection_feature)
#define KVM_INTROSPECTION_EVENT _IOW(KVMIO, 0xcb, struct kvm_introspection_feature)
+#define KVM_INTROSPECTION_PREUNHOOK _IO(KVMIO, 0xcc)
+
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)
#define KVM_DEV_ASSIGN_MASK_INTX (1 << 2)
@@ -384,3 +384,33 @@ int kvmi_ioctl_command(struct kvm *kvm,
mutex_unlock(&kvm->kvmi_lock);
return err;
}
+
+static bool kvmi_unhook_event(struct kvm_introspection *kvmi)
+{
+ int err;
+
+ err = kvmi_msg_send_unhook(kvmi);
+
+ return !err;
+}
+
+int kvmi_ioctl_preunhook(struct kvm *kvm)
+{
+ struct kvm_introspection *kvmi;
+ int err = 0;
+
+ mutex_lock(&kvm->kvmi_lock);
+
+ kvmi = KVMI(kvm);
+ if (!kvmi) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ if (!kvmi_unhook_event(kvmi))
+ err = -ENOENT;
+
+out:
+ mutex_unlock(&kvm->kvmi_lock);
+ return err;
+}
@@ -18,6 +18,7 @@ bool kvmi_sock_get(struct kvm_introspection *kvmi, int fd);
void kvmi_sock_shutdown(struct kvm_introspection *kvmi);
void kvmi_sock_put(struct kvm_introspection *kvmi);
bool kvmi_msg_process(struct kvm_introspection *kvmi);
+int kvmi_msg_send_unhook(struct kvm_introspection *kvmi);
/* kvmi.c */
void *kvmi_msg_alloc(void);
@@ -260,3 +260,8 @@ bool kvmi_msg_process(struct kvm_introspection *kvmi)
out:
return err == 0;
}
+
+int kvmi_msg_send_unhook(struct kvm_introspection *kvmi)
+{
+ return -1;
+}
@@ -4056,6 +4056,11 @@ static long kvm_vm_ioctl(struct file *filp,
r = kvmi_ioctl_command(kvm, &feat);
break;
}
+ case KVM_INTROSPECTION_PREUNHOOK:
+ r = -EPERM;
+ if (enable_introspection)
+ r = kvmi_ioctl_preunhook(kvm);
+ break;
#endif /* CONFIG_KVM_INTROSPECTION */
default:
r = kvm_arch_vm_ioctl(filp, ioctl, arg);
In certain situations (when the guest has to be paused, suspended, migrated, etc.), the device manager will use this new ioctl in order to trigger the KVMI_VM_EVENT_UNHOOK event. If the event is sent successfully (the VM has an active introspection channel), the device manager should delay the action (pause/suspend/...) to give the introspection tool the chance to remove its hooks (eg. breakpoints) while the guest is still running. Once a timeout is reached or the introspection tool has closed the socket, the device manager should resume the action. Signed-off-by: Adalbert Lazăr <alazar@bitdefender.com> --- Documentation/virt/kvm/api.rst | 28 ++++++++++++++++++++++++++++ Documentation/virt/kvm/kvmi.rst | 7 ++++--- include/linux/kvmi_host.h | 1 + include/uapi/linux/kvm.h | 2 ++ virt/kvm/introspection/kvmi.c | 30 ++++++++++++++++++++++++++++++ virt/kvm/introspection/kvmi_int.h | 1 + virt/kvm/introspection/kvmi_msg.c | 5 +++++ virt/kvm/kvm_main.c | 5 +++++ 8 files changed, 76 insertions(+), 3 deletions(-)