diff mbox series

[RFC,v5,04/20] kvm: add the VM introspection API/ABI headers

Message ID 20181220182850.4579-5-alazar@bitdefender.com (mailing list archive)
State New, archived
Headers show
Series VM introspection | expand

Commit Message

Adalbert Lazăr Dec. 20, 2018, 6:28 p.m. UTC
From: Mihai DONTU <mdontu@bitdefender.com>

And more KVM_E* error codes in kvm_para.h

Signed-off-by: Mihai Donțu <mdontu@bitdefender.com>
Signed-off-by: Adalbert Lazăr <alazar@bitdefender.com>
Signed-off-by: Nicușor Cîțu <ncitu@bitdefender.com>
Signed-off-by: Mircea Cîrjaliu <mcirjaliu@bitdefender.com>
Signed-off-by: Marian Rotariu <marian.c.rotariu@gmail.com>
---
 arch/x86/include/uapi/asm/kvmi.h | 234 +++++++++++++++++++++++++++++++
 include/uapi/linux/kvm.h         |  12 ++
 include/uapi/linux/kvm_para.h    |  11 +-
 include/uapi/linux/kvmi.h        | 192 +++++++++++++++++++++++++
 4 files changed, 448 insertions(+), 1 deletion(-)
 create mode 100644 arch/x86/include/uapi/asm/kvmi.h
 create mode 100644 include/uapi/linux/kvmi.h
diff mbox series

Patch

diff --git a/arch/x86/include/uapi/asm/kvmi.h b/arch/x86/include/uapi/asm/kvmi.h
new file mode 100644
index 000000000000..d114f82bc070
--- /dev/null
+++ b/arch/x86/include/uapi/asm/kvmi.h
@@ -0,0 +1,234 @@ 
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_ASM_X86_KVMI_H
+#define _UAPI_ASM_X86_KVMI_H
+
+/*
+ * KVMI x86 specific structures and definitions
+ *
+ */
+
+#include <asm/kvm.h>
+#include <linux/types.h>
+
+#define KVMI_EVENT_UNHOOK	0
+#define KVMI_EVENT_CR		1	/* control register was modified */
+#define KVMI_EVENT_MSR		2	/* model specific reg. was modified */
+#define KVMI_EVENT_XSETBV	3	/* ext. control register was modified */
+#define KVMI_EVENT_BREAKPOINT	4	/* breakpoint was reached */
+#define KVMI_EVENT_HYPERCALL	5	/* user hypercall */
+#define KVMI_EVENT_PF		6	/* hyp. page fault was encountered */
+#define KVMI_EVENT_TRAP		7	/* trap was injected */
+#define KVMI_EVENT_DESCRIPTOR	8	/* descriptor table access */
+#define KVMI_EVENT_CREATE_VCPU	9
+#define KVMI_EVENT_PAUSE_VCPU	10
+/* TODO: find a way to split the events between common and arch dependent */
+#define KVMI_NUM_EVENTS		11	/* increment with each added event */
+
+#define KVMI_EVENT_UNHOOK_FLAG		(1 << KVMI_EVENT_UNHOOK)
+#define KVMI_EVENT_CR_FLAG		(1 << KVMI_EVENT_CR)
+#define KVMI_EVENT_MSR_FLAG		(1 << KVMI_EVENT_MSR)
+#define KVMI_EVENT_XSETBV_FLAG		(1 << KVMI_EVENT_XSETBV)
+#define KVMI_EVENT_BREAKPOINT_FLAG	(1 << KVMI_EVENT_BREAKPOINT)
+#define KVMI_EVENT_HYPERCALL_FLAG	(1 << KVMI_EVENT_HYPERCALL)
+#define KVMI_EVENT_PF_FLAG		(1 << KVMI_EVENT_PF)
+#define KVMI_EVENT_TRAP_FLAG		(1 << KVMI_EVENT_TRAP)
+#define KVMI_EVENT_DESCRIPTOR_FLAG	(1 << KVMI_EVENT_DESCRIPTOR)
+#define KVMI_EVENT_CREATE_VCPU_FLAG	(1 << KVMI_EVENT_CREATE_VCPU)
+#define KVMI_EVENT_PAUSE_VCPU_FLAG	(1 << KVMI_EVENT_PAUSE_VCPU)
+
+#define KVMI_EVENT_ACTION_CONTINUE	0
+#define KVMI_EVENT_ACTION_RETRY		1
+#define KVMI_EVENT_ACTION_CRASH		2
+
+#define KVMI_KNOWN_VCPU_EVENTS ( \
+	KVMI_EVENT_CR_FLAG | \
+	KVMI_EVENT_MSR_FLAG | \
+	KVMI_EVENT_XSETBV_FLAG | \
+	KVMI_EVENT_BREAKPOINT_FLAG | \
+	KVMI_EVENT_HYPERCALL_FLAG | \
+	KVMI_EVENT_PF_FLAG | \
+	KVMI_EVENT_TRAP_FLAG | \
+	KVMI_EVENT_DESCRIPTOR_FLAG | \
+	KVMI_EVENT_PAUSE_VCPU_FLAG)
+
+#define KVMI_KNOWN_VM_EVENTS ( \
+	KVMI_EVENT_CREATE_VCPU_FLAG | \
+	KVMI_EVENT_UNHOOK_FLAG)
+
+#define KVMI_KNOWN_EVENTS (KVMI_KNOWN_VCPU_EVENTS | KVMI_KNOWN_VM_EVENTS)
+
+#define KVMI_ALLOWED_VM_EVENT(event_id, event_mask) \
+		((1 << (event_id)) & ((event_mask) & KVMI_KNOWN_VM_EVENTS))
+#define KVMI_ALLOWED_VCPU_EVENT(event_id, event_mask) \
+		((1 << (event_id)) & ((event_mask) & KVMI_KNOWN_VCPU_EVENTS))
+
+#define KVMI_PAGE_ACCESS_R (1 << 0)
+#define KVMI_PAGE_ACCESS_W (1 << 1)
+#define KVMI_PAGE_ACCESS_X (1 << 2)
+
+struct kvmi_event_cr {
+	__u16 cr;
+	__u16 padding[3];
+	__u64 old_value;
+	__u64 new_value;
+};
+
+struct kvmi_event_msr {
+	__u32 msr;
+	__u32 padding;
+	__u64 old_value;
+	__u64 new_value;
+};
+
+struct kvmi_event_breakpoint {
+	__u64 gpa;
+};
+
+struct kvmi_event_pf {
+	__u64 gva;
+	__u64 gpa;
+	__u32 mode;
+	__u32 padding;
+};
+
+struct kvmi_event_trap {
+	__u32 vector;
+	__u32 type;
+	__u32 error_code;
+	__u32 padding;
+	__u64 cr2;
+};
+
+#define KVMI_DESC_IDTR	1
+#define KVMI_DESC_GDTR	2
+#define KVMI_DESC_LDTR	3
+#define KVMI_DESC_TR	4
+
+struct kvmi_event_descriptor {
+	union {
+		struct {
+			__u32 instr_info;
+			__u32 padding;
+			__u64 exit_qualification;
+		} vmx;
+		struct {
+			__u64 exit_info;
+			__u64 padding;
+		} svm;
+	} arch;
+	__u8 descriptor;
+	__u8 write;
+	__u8 padding[6];
+};
+
+struct kvmi_event {
+	__u32 event;
+	__u16 vcpu;
+	__u8 mode;		/* 2, 4 or 8 */
+	__u8 padding;
+	struct kvm_regs regs;
+	struct kvm_sregs sregs;
+	struct {
+		__u64 sysenter_cs;
+		__u64 sysenter_esp;
+		__u64 sysenter_eip;
+		__u64 efer;
+		__u64 star;
+		__u64 lstar;
+		__u64 cstar;
+		__u64 pat;
+		__u64 shadow_gs;
+	} msrs;
+};
+
+struct kvmi_event_cr_reply {
+	__u64 new_val;
+};
+
+struct kvmi_event_msr_reply {
+	__u64 new_val;
+};
+
+struct kvmi_event_pf_reply {
+	__u8 singlestep;
+	__u8 rep_complete;
+	__u16 padding;
+	__u32 ctx_size;
+	__u8 ctx_data[256];
+};
+
+struct kvmi_control_cr {
+	__u16 vcpu;
+	__u8 enable;
+	__u8 padding;
+	__u32 cr;
+};
+
+struct kvmi_control_msr {
+	__u16 vcpu;
+	__u8 enable;
+	__u8 padding;
+	__u32 msr;
+};
+
+struct kvmi_guest_info {
+	__u16 vcpu_count;
+	__u16 padding1;
+	__u32 padding2;
+	__u64 tsc_speed;
+};
+
+struct kvmi_inject_exception {
+	__u16 vcpu;
+	__u8 nr;
+	__u8 has_error;
+	__u16 error_code;
+	__u16 padding;
+	__u64 address;
+};
+
+struct kvmi_get_registers {
+	__u16 vcpu;
+	__u16 nmsrs;
+	__u16 padding[2];
+	__u32 msrs_idx[0];
+};
+
+struct kvmi_get_registers_reply {
+	__u32 mode;
+	__u32 padding;
+	struct kvm_regs regs;
+	struct kvm_sregs sregs;
+	struct kvm_msrs msrs;
+};
+
+struct kvmi_set_registers {
+	__u16 vcpu;
+	__u16 padding[3];
+	struct kvm_regs regs;
+};
+
+struct kvmi_get_cpuid {
+	__u16 vcpu;
+	__u16 padding[3];
+	__u32 function;
+	__u32 index;
+};
+
+struct kvmi_get_cpuid_reply {
+	__u32 eax;
+	__u32 ebx;
+	__u32 ecx;
+	__u32 edx;
+};
+
+struct kvmi_get_xsave {
+	__u16 vcpu;
+	__u16 padding[3];
+};
+
+struct kvmi_get_xsave_reply {
+	__u32 region[0];
+};
+
+#endif /* _UAPI_ASM_X86_KVMI_H */
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 2b7a652c9fa4..f5028f20d441 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -976,6 +976,8 @@  struct kvm_ppc_resize_hpt {
 #define KVM_CAP_EXCEPTION_PAYLOAD 164
 #define KVM_CAP_ARM_VM_IPA_SIZE 165
 
+#define KVM_CAP_INTROSPECTION 999
+
 #ifdef KVM_CAP_IRQ_ROUTING
 
 struct kvm_irq_routing_irqchip {
@@ -1501,6 +1503,16 @@  struct kvm_sev_dbg {
 	__u32 len;
 };
 
+struct kvm_introspection {
+	int fd;
+	__u32 padding;
+	__u32 commands;
+	__u32 events;
+	__u8 uuid[16];
+};
+#define KVM_INTROSPECTION_HOOK    _IOW(KVMIO, 0xff, struct kvm_introspection)
+#define KVM_INTROSPECTION_UNHOOK  _IO(KVMIO,  0xfe)
+
 #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)
diff --git a/include/uapi/linux/kvm_para.h b/include/uapi/linux/kvm_para.h
index 6c0ce49931e5..2c2c32d99a5a 100644
--- a/include/uapi/linux/kvm_para.h
+++ b/include/uapi/linux/kvm_para.h
@@ -10,13 +10,18 @@ 
  * - kvm_para_available
  */
 
-/* Return values for hypercalls */
+/* Return values for hypercalls and VM introspection */
 #define KVM_ENOSYS		1000
 #define KVM_EFAULT		EFAULT
 #define KVM_EINVAL		EINVAL
 #define KVM_E2BIG		E2BIG
 #define KVM_EPERM		EPERM
 #define KVM_EOPNOTSUPP		95
+#define KVM_EAGAIN		11
+#define KVM_EBUSY		EBUSY
+#define KVM_ENOENT		ENOENT
+#define KVM_ENOMEM		ENOMEM
+#define KVM_EACCES		EACCES
 
 #define KVM_HC_VAPIC_POLL_IRQ		1
 #define KVM_HC_MMU_OP			2
@@ -29,6 +34,10 @@ 
 #define KVM_HC_CLOCK_PAIRING		9
 #define KVM_HC_SEND_IPI		10
 
+#define KVM_HC_MEM_MAP			32
+#define KVM_HC_MEM_UNMAP		33
+#define KVM_HC_XEN_HVM_OP		34 /* Xen's __HYPERVISOR_hvm_op */
+
 /*
  * hypercalls use architecture specific
  */
diff --git a/include/uapi/linux/kvmi.h b/include/uapi/linux/kvmi.h
new file mode 100644
index 000000000000..6b24825627bf
--- /dev/null
+++ b/include/uapi/linux/kvmi.h
@@ -0,0 +1,192 @@ 
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __UAPI_KVMI_H__
+#define __UAPI_KVMI_H__
+
+/*
+ * KVMI specific structures and definitions
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/kvmi.h>
+
+#define KVMI_VERSION 0x00000001
+
+#define KVMI_GET_VERSION		1
+#define KVMI_GET_GUEST_INFO		3
+#define KVMI_GET_REGISTERS		6
+#define KVMI_SET_REGISTERS		7
+#define KVMI_GET_PAGE_ACCESS		10
+#define KVMI_SET_PAGE_ACCESS		11
+#define KVMI_INJECT_EXCEPTION		12
+#define KVMI_READ_PHYSICAL		13
+#define KVMI_WRITE_PHYSICAL		14
+#define KVMI_GET_MAP_TOKEN		15
+#define KVMI_CONTROL_EVENTS		17
+#define KVMI_CONTROL_CR			18
+#define KVMI_CONTROL_MSR		19
+#define KVMI_EVENT			23
+#define KVMI_EVENT_REPLY		24
+#define KVMI_GET_CPUID			25
+#define KVMI_GET_XSAVE			26
+#define KVMI_PAUSE_ALL_VCPUS		27
+#define KVMI_CONTROL_VM_EVENTS		28
+
+/* TODO: find a way to split the commands between common and arch dependent */
+
+#define KVMI_GET_VERSION_FLAG		(1 << KVMI_GET_VERSION)
+#define KVMI_GET_GUEST_INFO_FLAG	(1 << KVMI_GET_GUEST_INFO)
+#define KVMI_GET_REGISTERS_FLAG		(1 << KVMI_GET_REGISTERS)
+#define KVMI_SET_REGISTERS_FLAG		(1 << KVMI_SET_REGISTERS)
+#define KVMI_GET_PAGE_ACCESS_FLAG	(1 << KVMI_GET_PAGE_ACCESS)
+#define KVMI_SET_PAGE_ACCESS_FLAG	(1 << KVMI_SET_PAGE_ACCESS)
+#define KVMI_INJECT_EXCEPTION_FLAG	(1 << KVMI_INJECT_EXCEPTION)
+#define KVMI_READ_PHYSICAL_FLAG		(1 << KVMI_READ_PHYSICAL)
+#define KVMI_WRITE_PHYSICAL_FLAG	(1 << KVMI_WRITE_PHYSICAL)
+#define KVMI_GET_MAP_TOKEN_FLAG		(1 << KVMI_GET_MAP_TOKEN)
+#define KVMI_CONTROL_EVENTS_FLAG	(1 << KVMI_CONTROL_EVENTS)
+#define KVMI_CONTROL_CR_FLAG		(1 << KVMI_CONTROL_CR)
+#define KVMI_CONTROL_MSR_FLAG		(1 << KVMI_CONTROL_MSR)
+#define KVMI_EVENT_FLAG			(1 << KVMI_EVENT)
+#define KVMI_EVENT_REPLY_FLAG		(1 << KVMI_EVENT_REPLY)
+#define KVMI_GET_CPUID_FLAG		(1 << KVMI_GET_CPUID)
+#define KVMI_GET_XSAVE_FLAG		(1 << KVMI_GET_XSAVE)
+#define KVMI_PAUSE_ALL_VCPUS_FLAG	(1 << KVMI_PAUSE_ALL_VCPUS)
+#define KVMI_CONTROL_VM_EVENTS_FLAG	(1 << KVMI_CONTROL_VM_EVENTS)
+
+#define KVMI_KNOWN_COMMANDS (\
+	KVMI_GET_VERSION_FLAG | \
+	KVMI_GET_GUEST_INFO_FLAG | \
+	KVMI_GET_REGISTERS_FLAG | \
+	KVMI_SET_REGISTERS_FLAG | \
+	KVMI_GET_PAGE_ACCESS_FLAG | \
+	KVMI_SET_PAGE_ACCESS_FLAG | \
+	KVMI_INJECT_EXCEPTION_FLAG | \
+	KVMI_READ_PHYSICAL_FLAG | \
+	KVMI_WRITE_PHYSICAL_FLAG | \
+	KVMI_GET_MAP_TOKEN_FLAG | \
+	KVMI_CONTROL_EVENTS_FLAG | \
+	KVMI_CONTROL_CR_FLAG | \
+	KVMI_CONTROL_MSR_FLAG | \
+	KVMI_EVENT_FLAG | \
+	KVMI_EVENT_REPLY_FLAG | \
+	KVMI_GET_CPUID_FLAG | \
+	KVMI_GET_XSAVE_FLAG | \
+	KVMI_PAUSE_ALL_VCPUS_FLAG | \
+	KVMI_CONTROL_VM_EVENTS_FLAG)
+
+#define KVMI_ALLOWED_COMMAND(cmd_id, cmd_mask) \
+		((1 << (cmd_id)) & ((cmd_mask) & KVMI_KNOWN_COMMANDS))
+
+#define KVMI_MSG_SIZE 4096
+
+struct kvmi_msg_hdr {
+	__u16 id;
+	__u16 size;
+	__u32 seq;
+};
+
+struct kvmi_error_code {
+	__s32 err;
+	__u32 padding;
+};
+
+struct kvmi_get_version_reply {
+	__u32 version;
+	__u32 commands;
+	__u32 events;
+	__u32 padding;
+};
+
+struct kvmi_get_guest_info {
+	__u16 vcpu;
+	__u16 padding[3];
+};
+
+struct kvmi_get_guest_info_reply {
+	__u32 vcpu_count;
+	__u32 padding;
+	__u64 tsc_speed;
+};
+
+struct kvmi_pause_all_vcpus_reply {
+	__u32 vcpu_count;
+	__u32 padding;
+};
+
+struct kvmi_event_reply {
+	__u32 action;
+	__u32 event;
+};
+
+struct kvmi_control_events {
+	__u16 vcpu;
+	__u16 padding;
+	__u32 events;
+};
+
+struct kvmi_control_vm_events {
+	__u32 events;
+	__u32 padding;
+};
+
+struct kvmi_get_page_access {
+	__u16 vcpu;
+	__u16 count;
+	__u16 view;
+	__u16 padding;
+	__u64 gpa[0];
+};
+
+struct kvmi_get_page_access_reply {
+	__u8 access[0];
+};
+
+struct kvmi_page_access_entry {
+	__u64 gpa;
+	__u8 access;
+	__u8 padding[7];
+};
+
+struct kvmi_set_page_access {
+	__u16 vcpu;
+	__u16 count;
+	__u16 view;
+	__u16 padding;
+	struct kvmi_page_access_entry entries[0];
+};
+
+struct kvmi_read_physical {
+	__u64 gpa;
+	__u64 size;
+};
+
+struct kvmi_write_physical {
+	__u64 gpa;
+	__u64 size;
+	__u8  data[0];
+};
+
+struct kvmi_map_mem_token {
+	__u64 token[4];
+};
+
+struct kvmi_get_map_token_reply {
+	struct kvmi_map_mem_token token;
+};
+
+/* Map other guest's gpa to local gva */
+struct kvmi_mem_map {
+	struct kvmi_map_mem_token token;
+	__u64 gpa;
+	__u64 gva;
+};
+
+/*
+ * ioctls for /dev/kvmmem
+ */
+#define KVM_INTRO_MEM_MAP	_IOW('i', 0x01, struct kvmi_mem_map)
+#define KVM_INTRO_MEM_UNMAP	_IOW('i', 0x02, unsigned long)
+
+#endif /* __UAPI_KVMI_H__ */