diff mbox series

[RFC,v1,25/26] kvm: vmi: extend handshake to include the e820 table

Message ID 20200415005938.23895-26-alazar@bitdefender.com
State New
Headers show
Series VM introspection | expand

Commit Message

Adalbert Lazăr April 15, 2020, 12:59 a.m. UTC
The introspection tool can use the e820 table to avoid accessing
(read/write) or modifying access (rwx) for reserved memory pages.

Signed-off-by: Adalbert Lazăr <alazar@bitdefender.com>
---
 accel/kvm/vmi.c                | 68 ++++++++++++++++++++++++++++++----
 include/sysemu/vmi-handshake.h | 23 +++++++++++-
 2 files changed, 82 insertions(+), 9 deletions(-)
diff mbox series

Patch

diff --git a/accel/kvm/vmi.c b/accel/kvm/vmi.c
index 02877eec06..f70d78848a 100644
--- a/accel/kvm/vmi.c
+++ b/accel/kvm/vmi.c
@@ -26,6 +26,7 @@ 
 #include "migration/misc.h"
 #include "qapi/qmp/qobject.h"
 #include "monitor/monitor.h"
+#include "hw/i386/e820_memory_layout.h"
 
 #include "sysemu/vmi-intercept.h"
 #include "sysemu/vmi-handshake.h"
@@ -412,23 +413,74 @@  static void register_types(void)
 
 type_init(register_types);
 
+static uint8_t handshake_cpu_type(void)
+{
+#ifdef TARGET_X86_64
+    return QEMU_VMI_CPU_TYPE_X86_64;
+#elif TARGET_I386
+    return QEMU_VMI_CPU_TYPE_I386;
+#else
+    return QEMU_VMI_CPU_TYPE_UNKNOWN;
+#endif
+}
+
+static int cmp_address(const void *a, const void *b)
+{
+    uint64_t addr_a = ((qemu_vmi_e820_entry *)a)->address;
+    uint64_t addr_b = ((qemu_vmi_e820_entry *)b)->address;
+
+    return (addr_a > addr_b) - (addr_a < addr_b);
+}
+
+static void fill_e820_info(qemu_vmi_e820_entry *dest, int n)
+{
+    int idx;
+
+    for (idx = 0; idx < n; idx++)
+        e820_get_entry2(idx, &dest[idx].type, &dest[idx].address,
+                        &dest[idx].length);
+
+    qsort(dest, n, sizeof(*dest), cmp_address);
+}
+
 static bool send_handshake_info(VMIntrospection *i, Error **errp)
 {
-    qemu_vmi_to_introspector send = {};
+    qemu_vmi_to_introspector *send;
+    int max_n_e820, n_e820;
     const char *vm_name;
+    size_t send_sz;
     int r;
 
-    send.struct_size = sizeof(send);
-    send.start_time = i->vm_start_time;
-    memcpy(&send.uuid, &qemu_uuid, sizeof(send.uuid));
+    max_n_e820 = 8 * sizeof(((qemu_vmi_to_introspector *)0)->arch.e820_count);
+    n_e820 = e820_get_num_entries();
+
+    if (n_e820 < 0 || n_e820 > max_n_e820) {
+        warn_report("VMI: discard e820 info (size %d, max %d)",
+                    n_e820, max_n_e820);
+        n_e820 = 0;
+    }
+
+    send_sz = sizeof(*send) + n_e820 * sizeof(qemu_vmi_e820_entry);
+
+    send = g_malloc0(send_sz);
+
+    send->struct_size = send_sz;
+    send->start_time = i->vm_start_time;
+    send->cpu_type = handshake_cpu_type();
+    memcpy(&send->uuid, &qemu_uuid, sizeof(send->uuid));
     vm_name = qemu_get_vm_name();
     if (vm_name) {
-        snprintf(send.name, sizeof(send.name), "%s", vm_name);
-        send.name[sizeof(send.name) - 1] = 0;
+        snprintf(send->name, sizeof(send->name), "%s", vm_name);
+        send->name[sizeof(send->name) - 1] = 0;
+    }
+    send->arch.e820_count = n_e820;
+    if (n_e820) {
+        fill_e820_info(send->arch.e820_entries, n_e820);
     }
 
-    r = qemu_chr_fe_write_all(&i->sock, (uint8_t *)&send, sizeof(send));
-    if (r != sizeof(send)) {
+    r = qemu_chr_fe_write_all(&i->sock, (uint8_t *)send, send_sz);
+    g_free(send);
+    if (r != send_sz) {
         error_setg_errno(errp, errno, "VMI: error writing to '%s'",
                          i->chardevid);
         return false;
diff --git a/include/sysemu/vmi-handshake.h b/include/sysemu/vmi-handshake.h
index 19bdfb6740..3c5201d37b 100644
--- a/include/sysemu/vmi-handshake.h
+++ b/include/sysemu/vmi-handshake.h
@@ -9,6 +9,25 @@ 
 enum { QEMU_VMI_NAME_SIZE = 64 };
 enum { QEMU_VMI_COOKIE_HASH_SIZE = 20};
 
+enum {
+    QEMU_VMI_CPU_TYPE_I386 = 0,
+    QEMU_VMI_CPU_TYPE_X86_64 = 1,
+    QEMU_VMI_CPU_TYPE_UNKNOWN = 255
+};
+
+typedef struct qemu_vmi_e820_entry {
+    uint64_t address;
+    uint64_t length;
+    uint32_t type;
+    uint32_t padding;
+} qemu_vmi_e820_entry;
+
+typedef struct qemu_vmi_to_introspector_x86 {
+   uint8_t e820_count;
+   uint8_t padding[3];
+   qemu_vmi_e820_entry e820_entries[0];
+} qemu_vmi_to_introspector_x86;
+
 /**
  * qemu_vmi_to_introspector:
  *
@@ -22,9 +41,11 @@  enum { QEMU_VMI_COOKIE_HASH_SIZE = 20};
 typedef struct qemu_vmi_to_introspector {
     uint32_t struct_size;
     uint8_t  uuid[16];
-    uint32_t padding;
+    uint8_t  cpu_type;
+    uint8_t  padding[3];
     int64_t  start_time;
     char     name[QEMU_VMI_NAME_SIZE];
+    qemu_vmi_to_introspector_x86 arch;
     /* ... */
 } qemu_vmi_to_introspector;