9ae3a8
From 713d4d69d84774949c7306289724c2463dbeab1d Mon Sep 17 00:00:00 2001
9ae3a8
From: Laszlo Ersek <lersek@redhat.com>
9ae3a8
Date: Mon, 1 Sep 2014 13:36:53 +0200
9ae3a8
Subject: [PATCH 06/12] vmstate_xhci_event: bug compat with RHEL-7.0 (RHEL only)
9ae3a8
9ae3a8
Message-id: <1409578613-11909-3-git-send-email-lersek@redhat.com>
9ae3a8
Patchwork-id: 60782
9ae3a8
O-Subject: [PATCH RHEL-7.0.z/RHEL-7.1.0 qemu-kvm 2/2] vmstate_xhci_event: bug compat with RHEL-7.0 (RHEL only)
9ae3a8
Bugzilla: 1122147
9ae3a8
RH-Acked-by: Dr. David Alan Gilbert (git) <dgilbert@redhat.com>
9ae3a8
RH-Acked-by: Amit Shah <amit.shah@redhat.com>
9ae3a8
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
9ae3a8
9ae3a8
The "vmstate_xhci_event.fields" member is a pointer to an array of
9ae3a8
VMStateField elements. The unnamed array (of static storage duration)
9ae3a8
comes from a compound literal. The previous patch fixed the undefined
9ae3a8
behavior by adding a terminator element to this array, but in RHEL-7 we
9ae3a8
also need to look into the practical details of that undefined behavior.
9ae3a8
9ae3a8
In debug builds (./configure --enable-debug), the compiler places the
9ae3a8
"vmstate_xhci_intr.fields" member's unnamed initializer array right after
9ae3a8
the "vmstate_xhci_event.fields" member's. This leads to infinite recursion
9ae3a8
(see the previous patch for details), but in RHEL-7 we don't ship debug
9ae3a8
builds.
9ae3a8
9ae3a8
In a normal (optimized, official) build, the layout changes. The
9ae3a8
"vmstate_xhci_event.fields" member's unterminated initializer array is
9ae3a8
followed by the one of the "vmstate_xhci_slot.fields" member:
9ae3a8
9ae3a8
  (gdb) print (intptr_t)&vmstate_xhci_event.fields[7] - \
9ae3a8
              (intptr_t)&vmstate_xhci_slot.fields[0]
9ae3a8
  $3 = 0
9ae3a8
9ae3a8
where "vmstate_xhci_slot.fields" is initialized from
9ae3a8
9ae3a8
    .fields = (VMStateField[]) {
9ae3a8
        VMSTATE_BOOL(enabled,   XHCISlot),
9ae3a8
        VMSTATE_BOOL(addressed, XHCISlot),
9ae3a8
        VMSTATE_END_OF_LIST()
9ae3a8
    }
9ae3a8
9ae3a8
The elements of this array are (only relevant members quoted):
9ae3a8
9ae3a8
  (gdb) print vmstate_xhci_slot.fields[0].offset
9ae3a8
  $16 = 0
9ae3a8
  (gdb) print vmstate_xhci_slot.fields[0].size
9ae3a8
  $17 = 1
9ae3a8
  (gdb) print vmstate_xhci_slot.fields[1].offset
9ae3a8
  $18 = 1
9ae3a8
  (gdb) print vmstate_xhci_slot.fields[1].size
9ae3a8
  $19 = 1
9ae3a8
9ae3a8
This means that the wire format for "vmstate_xhci_event" will include the
9ae3a8
byte at offset 0 and the byte at offset 1 from XHCIEvent, corresponding to
9ae3a8
part of the "XHCIEvent.type" member:
9ae3a8
9ae3a8
  (gdb) print vmstate_xhci_event.fields[0].name
9ae3a8
  $23 = 0x5555558b12e7 "type"
9ae3a8
  (gdb) print vmstate_xhci_event.fields[0].offset
9ae3a8
  $24 = 0
9ae3a8
  (gdb) print vmstate_xhci_event.fields[0].size
9ae3a8
  $25 = 4
9ae3a8
9ae3a8
In order to accommodate these bogus bytes, coming from an unpatched source
9ae3a8
side, we introduce two dummy XHCIEvent fields; otherwise the patched
9ae3a8
destination would reject the migration stream.
9ae3a8
9ae3a8
For the reverse direction, we explicitly set the dummy bytes to the values
9ae3a8
that they used to take in an unpatched source, so that when the unpatched
9ae3a8
destination deserializes them into part of "XHCIEvent.type", said victim
9ae3a8
member still receives a correct value.
9ae3a8
9ae3a8
The dummy fields have type uint8_t, not bool. The reason is that
9ae3a8
assignment to bool (in xhci_event_pre_save()) would entail conversion to
9ae3a8
bool, hence result in values 0 or 1. (See _Bool conversion rules and
9ae3a8
<stdbool.h>.)
9ae3a8
9ae3a8
RHEL-only because we control the compiler version and the build flags only
9ae3a8
in RHEL.
9ae3a8
9ae3a8
This is for CVE-2014-5263.
9ae3a8
9ae3a8
Suggested-by: Amit Shah <amit.shah@redhat.com>
9ae3a8
Suggested-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
9ae3a8
Suggested-by: Markus Armbruster <armbru@redhat.com>
9ae3a8
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
9ae3a8
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9ae3a8
---
9ae3a8
 hw/usb/hcd-xhci.c |   27 ++++++++++++++++++++-------
9ae3a8
 1 files changed, 20 insertions(+), 7 deletions(-)
9ae3a8
9ae3a8
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
9ae3a8
index 0ef2bc4..2c9e36a 100644
9ae3a8
--- a/hw/usb/hcd-xhci.c
9ae3a8
+++ b/hw/usb/hcd-xhci.c
9ae3a8
@@ -420,6 +420,8 @@ typedef struct XHCIEvent {
9ae3a8
     uint32_t flags;
9ae3a8
     uint8_t slotid;
9ae3a8
     uint8_t epid;
9ae3a8
+    uint8_t cve_2014_5263_a;
9ae3a8
+    uint8_t cve_2014_5263_b;
9ae3a8
 } XHCIEvent;
9ae3a8
 
9ae3a8
 typedef struct XHCIInterrupter {
9ae3a8
@@ -3515,17 +3517,28 @@ static const VMStateDescription vmstate_xhci_slot = {
9ae3a8
     }
9ae3a8
 };
9ae3a8
 
9ae3a8
+static void xhci_event_pre_save(void *opaque)
9ae3a8
+{
9ae3a8
+    XHCIEvent *s = opaque;
9ae3a8
+
9ae3a8
+    s->cve_2014_5263_a = ((uint8_t *)&s->type)[0];
9ae3a8
+    s->cve_2014_5263_b = ((uint8_t *)&s->type)[1];
9ae3a8
+}
9ae3a8
+
9ae3a8
 static const VMStateDescription vmstate_xhci_event = {
9ae3a8
     .name = "xhci-event",
9ae3a8
     .version_id = 1,
9ae3a8
+    .pre_save = xhci_event_pre_save,
9ae3a8
     .fields = (VMStateField[]) {
9ae3a8
-        VMSTATE_UINT32(type,   XHCIEvent),
9ae3a8
-        VMSTATE_UINT32(ccode,  XHCIEvent),
9ae3a8
-        VMSTATE_UINT64(ptr,    XHCIEvent),
9ae3a8
-        VMSTATE_UINT32(length, XHCIEvent),
9ae3a8
-        VMSTATE_UINT32(flags,  XHCIEvent),
9ae3a8
-        VMSTATE_UINT8(slotid,  XHCIEvent),
9ae3a8
-        VMSTATE_UINT8(epid,    XHCIEvent),
9ae3a8
+        VMSTATE_UINT32(type,           XHCIEvent),
9ae3a8
+        VMSTATE_UINT32(ccode,          XHCIEvent),
9ae3a8
+        VMSTATE_UINT64(ptr,            XHCIEvent),
9ae3a8
+        VMSTATE_UINT32(length,         XHCIEvent),
9ae3a8
+        VMSTATE_UINT32(flags,          XHCIEvent),
9ae3a8
+        VMSTATE_UINT8(slotid,          XHCIEvent),
9ae3a8
+        VMSTATE_UINT8(epid,            XHCIEvent),
9ae3a8
+        VMSTATE_UINT8(cve_2014_5263_a, XHCIEvent),
9ae3a8
+        VMSTATE_UINT8(cve_2014_5263_b, XHCIEvent),
9ae3a8
         VMSTATE_END_OF_LIST()
9ae3a8
     }
9ae3a8
 };
9ae3a8
-- 
9ae3a8
1.7.1
9ae3a8