9ae3a8
From 9a2ab369a3685f85dfa7449c31a2267333cb1468 Mon Sep 17 00:00:00 2001
9ae3a8
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
9ae3a8
Date: Wed, 13 Dec 2017 13:39:02 +0100
9ae3a8
Subject: [PATCH 31/41] dump: update phys_base header field based on VMCOREINFO
9ae3a8
 content
9ae3a8
MIME-Version: 1.0
9ae3a8
Content-Type: text/plain; charset=UTF-8
9ae3a8
Content-Transfer-Encoding: 8bit
9ae3a8
9ae3a8
RH-Author: Marc-André Lureau <marcandre.lureau@redhat.com>
9ae3a8
Message-id: <20171213133912.26176-32-marcandre.lureau@redhat.com>
9ae3a8
Patchwork-id: 78380
9ae3a8
O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 31/41] dump: update phys_base header field based on VMCOREINFO content
9ae3a8
Bugzilla: 1411490
9ae3a8
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
9ae3a8
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
9ae3a8
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
9ae3a8
If the guest note is VMCOREINFO, try to get phys_base from it.
9ae3a8
9ae3a8
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
9ae3a8
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
9ae3a8
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
9ae3a8
9ae3a8
(cherry picked from commit d9feb51772b4ade9700c7fa54529327a6c8183a7)
9ae3a8
9ae3a8
RHEL: replace qemu_strotu64() usage, warn_report()->error_report()
9ae3a8
9ae3a8
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 docs/specs/vmcoreinfo.txt |  8 +++++++
9ae3a8
 dump.c                    | 57 +++++++++++++++++++++++++++++++++++++++++++++--
9ae3a8
 2 files changed, 63 insertions(+), 2 deletions(-)
9ae3a8
9ae3a8
diff --git a/docs/specs/vmcoreinfo.txt b/docs/specs/vmcoreinfo.txt
9ae3a8
index 2868a77..8212610 100644
9ae3a8
--- a/docs/specs/vmcoreinfo.txt
9ae3a8
+++ b/docs/specs/vmcoreinfo.txt
9ae3a8
@@ -39,3 +39,11 @@ qemu dumps.
9ae3a8
 
9ae3a8
 The note format/class must be of the target bitness and the size must
9ae3a8
 be less than 1Mb.
9ae3a8
+
9ae3a8
+If the ELF note name is "VMCOREINFO", it is expected to be the Linux
9ae3a8
+vmcoreinfo note (see Documentation/ABI/testing/sysfs-kernel-vmcoreinfo
9ae3a8
+in Linux source). In this case, qemu dump code will read the content
9ae3a8
+as a key=value text file, looking for "NUMBER(phys_base)" key
9ae3a8
+value. The value is expected to be more accurate than architecture
9ae3a8
+guess of the value. This is useful for KASLR-enabled guest with
9ae3a8
+ancient tools not handling the VMCOREINFO note.
9ae3a8
diff --git a/dump.c b/dump.c
9ae3a8
index 823d1ad..3bce730 100644
9ae3a8
--- a/dump.c
9ae3a8
+++ b/dump.c
9ae3a8
@@ -777,6 +777,23 @@ static void get_note_sizes(DumpState *s, const void *note,
9ae3a8
     }
9ae3a8
 }
9ae3a8
 
9ae3a8
+static bool note_name_equal(DumpState *s,
9ae3a8
+                            const uint8_t *note, const char *name)
9ae3a8
+{
9ae3a8
+    int len = strlen(name) + 1;
9ae3a8
+    uint64_t head_size, name_size;
9ae3a8
+
9ae3a8
+    get_note_sizes(s, note, &head_size, &name_size, NULL);
9ae3a8
+    head_size = ROUND_UP(head_size, 4);
9ae3a8
+
9ae3a8
+    if (name_size != len ||
9ae3a8
+        memcmp(note + head_size, "VMCOREINFO", len)) {
9ae3a8
+        return false;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    return true;
9ae3a8
+}
9ae3a8
+
9ae3a8
 /* write common header, sub header and elf note to vmcore */
9ae3a8
 static void create_header32(DumpState *s, Error **errp)
9ae3a8
 {
9ae3a8
@@ -1553,6 +1570,40 @@ static int64_t dump_calculate_size(DumpState *s)
9ae3a8
     return total;
9ae3a8
 }
9ae3a8
 
9ae3a8
+static void vmcoreinfo_update_phys_base(DumpState *s)
9ae3a8
+{
9ae3a8
+    uint64_t size, note_head_size, name_size, phys_base;
9ae3a8
+    char **lines;
9ae3a8
+    uint8_t *vmci;
9ae3a8
+    size_t i;
9ae3a8
+
9ae3a8
+    if (!note_name_equal(s, s->guest_note, "VMCOREINFO")) {
9ae3a8
+        return;
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    get_note_sizes(s, s->guest_note, ¬e_head_size, &name_size, &size);
9ae3a8
+    note_head_size = ROUND_UP(note_head_size, 4);
9ae3a8
+
9ae3a8
+    vmci = s->guest_note + note_head_size + ROUND_UP(name_size, 4);
9ae3a8
+    *(vmci + size) = '\0';
9ae3a8
+
9ae3a8
+    lines = g_strsplit((char *)vmci, "\n", -1);
9ae3a8
+    for (i = 0; lines[i]; i++) {
9ae3a8
+        if (g_str_has_prefix(lines[i], "NUMBER(phys_base)=")) {
9ae3a8
+            errno = 0;
9ae3a8
+            phys_base = strtoull(lines[i] + 18, NULL, 16);
9ae3a8
+            if (errno == ERANGE) {
9ae3a8
+                error_report("Failed to read NUMBER(phys_base)=");
9ae3a8
+            } else {
9ae3a8
+                s->dump_info.phys_base = phys_base;
9ae3a8
+            }
9ae3a8
+            break;
9ae3a8
+        }
9ae3a8
+    }
9ae3a8
+
9ae3a8
+    g_strfreev(lines);
9ae3a8
+}
9ae3a8
+
9ae3a8
 static void dump_init(DumpState *s, int fd, bool has_format,
9ae3a8
                       DumpGuestMemoryFormat format, bool paging, bool has_filter,
9ae3a8
                       int64_t begin, int64_t length, Error **errp)
9ae3a8
@@ -1636,8 +1687,9 @@ static void dump_init(DumpState *s, int fd, bool has_format,
9ae3a8
     }
9ae3a8
 
9ae3a8
     /*
9ae3a8
-     * The goal of this block is to copy the guest note out of
9ae3a8
-     * the guest.  Failure to do so is not fatal for dumping.
9ae3a8
+     * The goal of this block is to (a) update the previously guessed
9ae3a8
+     * phys_base, (b) copy the guest note out of the guest.
9ae3a8
+     * Failure to do so is not fatal for dumping.
9ae3a8
      */
9ae3a8
     if (vmci) {
9ae3a8
         uint64_t addr, note_head_size, name_size, desc_size;
9ae3a8
@@ -1670,6 +1722,7 @@ static void dump_init(DumpState *s, int fd, bool has_format,
9ae3a8
                 g_free(s->guest_note);
9ae3a8
                 s->guest_note = NULL;
9ae3a8
             } else {
9ae3a8
+                vmcoreinfo_update_phys_base(s);
9ae3a8
                 s->note_size += s->guest_note_size;
9ae3a8
             }
9ae3a8
         }
9ae3a8
-- 
9ae3a8
1.8.3.1
9ae3a8