619821
From 2ee2492513f9685cb716dc1cb4cf5b580da43e07 Mon Sep 17 00:00:00 2001
619821
From: Bandan Das <bsd@redhat.com>
619821
Date: Wed, 25 Jan 2017 03:36:07 +0100
619821
Subject: [PATCH 01/11] memory: Allow access only upto the maximum alignment
619821
 for memory_region_* functions
619821
619821
RH-Author: Bandan Das <bsd@redhat.com>
619821
Message-id: <jpgefzrn74o.fsf@linux.bootlegged.copy>
619821
Patchwork-id: 73367
619821
O-Subject: [RHEL-7.4 qemu-kvm PATCH] memory: Allow access only upto the maximum alignment for memory_region_* functions
619821
Bugzilla: 1342768
619821
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
619821
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
619821
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
619821
619821
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1342768
619821
Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=12437870
619821
Upstream: N/A, upstream doesn't exhibit this behavior
619821
619821
Currently, there is no check in memory_region_iorange_* functions for whether
619821
the size requested is greater than the maximum alignment. This causes
619821
an abort with a specific version of the Linux kernel (4.7.0-RC1):
619821
/usr/libexec/qemu-kvm -kernel ~/vmlinuz-4.7.0-rc1 --enable-kvm -m 1G -vnc :2 -monitor stdio
619821
619821
0  0x00007fb057cb65f7 in raise () from /lib64/libc.so.6
619821
1  0x00007fb057cb7ce8 in abort () from /lib64/libc.so.6
619821
2  0x00007fb05eca5537 in acpi_gpe_ioport_readb ()
619821
3  0x00007fb05eca5ff0 in gpe_readb ()
619821
4  0x00007fb05ede6f4c in memory_region_read_accessor ()
619821
5  0x00007fb05ede6993 in access_with_adjusted_size ()
619821
6  0x00007fb05ede7ce8 in memory_region_iorange_read ()
619821
7  0x00007fb05ede2ac7 in ioport_readl_thunk ()
619821
8  0x00007fb05ede3141 in cpu_inl ()
619821
9  0x00007fb05ede5c49 in kvm_cpu_exec ()
619821
10 0x00007fb05ed98485 in qemu_kvm_cpu_thread_fn ()
619821
11 0x00007fb05bcc9dc5 in start_thread () from /lib64/libpthread.so.0
619821
12 0x00007fb057d77ced in clone () from /lib64/libc.so.6
619821
619821
This happens because guest code tries to read(l=4) from 0xafe2
619821
with GPE base being 0xafe0 which causes the abort in
619821
acpi_gpe_ioport_get_ptr() to trigger. This change adds a
619821
memory_access_size() which is similar to the one in upstream that
619821
forces size to be equal to the maximum alignment if it's greater.
619821
It also keeps the other checks present in upstream for safety and
619821
is called from the memory_region_read/write functions before
619821
calling the call specific access functions.
619821
619821
Signed-off-by: Bandan Das <bsd@redhat.com>
619821
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
619821
---
619821
 memory.c | 44 ++++++++++++++++++++++++++++++++++++++++----
619821
 1 file changed, 40 insertions(+), 4 deletions(-)
619821
619821
diff --git a/memory.c b/memory.c
619821
index 7bd6e87..573ecdd 100644
619821
--- a/memory.c
619821
+++ b/memory.c
619821
@@ -381,6 +381,33 @@ static const MemoryRegionPortio *find_portio(MemoryRegion *mr, uint64_t offset,
619821
     return NULL;
619821
 }
619821
 
619821
+static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
619821
+{
619821
+  unsigned access_size_max = mr->ops->valid.max_access_size;
619821
+
619821
+  /* Regions are assumed to support 1-4 byte accesses unless
619821
+     otherwise specified.  */
619821
+  if (access_size_max == 0) {
619821
+    access_size_max = 4;
619821
+  }
619821
+
619821
+  /* Bound the maximum access by the alignment of the address.  */
619821
+  if (!mr->ops->impl.unaligned) {
619821
+    unsigned align_size_max = addr & -addr;
619821
+    if (align_size_max != 0 && align_size_max < access_size_max) {
619821
+        access_size_max = align_size_max;
619821
+    }
619821
+  }
619821
+
619821
+  /* Don't attempt accesses larger than the maximum.  */
619821
+  if (l > access_size_max) {
619821
+    l = access_size_max;
619821
+  }
619821
+  l = pow2floor(l);
619821
+
619821
+  return l;
619821
+}
619821
+
619821
 static void memory_region_iorange_read(IORange *iorange,
619821
                                        uint64_t offset,
619821
                                        unsigned width,
619821
@@ -389,6 +416,7 @@ static void memory_region_iorange_read(IORange *iorange,
619821
     MemoryRegionIORange *mrio
619821
         = container_of(iorange, MemoryRegionIORange, iorange);
619821
     MemoryRegion *mr = mrio->mr;
619821
+    unsigned l;
619821
 
619821
     offset += mrio->offset;
619821
     if (mr->ops->old_portio) {
619821
@@ -407,7 +435,8 @@ static void memory_region_iorange_read(IORange *iorange,
619821
         return;
619821
     }
619821
     *data = 0;
619821
-    access_with_adjusted_size(offset, data, width,
619821
+    l = memory_access_size(mr, width, offset);
619821
+    access_with_adjusted_size(offset, data, l,
619821
                               mr->ops->impl.min_access_size,
619821
                               mr->ops->impl.max_access_size,
619821
                               memory_region_read_accessor, mr);
619821
@@ -421,6 +450,7 @@ static void memory_region_iorange_write(IORange *iorange,
619821
     MemoryRegionIORange *mrio
619821
         = container_of(iorange, MemoryRegionIORange, iorange);
619821
     MemoryRegion *mr = mrio->mr;
619821
+    unsigned l;
619821
 
619821
     offset += mrio->offset;
619821
     if (mr->ops->old_portio) {
619821
@@ -437,7 +467,8 @@ static void memory_region_iorange_write(IORange *iorange,
619821
         }
619821
         return;
619821
     }
619821
-    access_with_adjusted_size(offset, &data, width,
619821
+    l = memory_access_size(mr, width, offset);
619821
+    access_with_adjusted_size(offset, &data, l,
619821
                               mr->ops->impl.min_access_size,
619821
                               mr->ops->impl.max_access_size,
619821
                               memory_region_write_accessor, mr);
619821
@@ -850,6 +881,7 @@ static uint64_t memory_region_dispatch_read1(MemoryRegion *mr,
619821
                                              unsigned size)
619821
 {
619821
     uint64_t data = 0;
619821
+    unsigned l;
619821
 
619821
     if (!memory_region_access_valid(mr, addr, size, false)) {
619821
         return -1U; /* FIXME: better signalling */
619821
@@ -859,8 +891,9 @@ static uint64_t memory_region_dispatch_read1(MemoryRegion *mr,
619821
         return mr->ops->old_mmio.read[ctz32(size)](mr->opaque, addr);
619821
     }
619821
 
619821
+    l = memory_access_size(mr, size, addr);
619821
     /* FIXME: support unaligned access */
619821
-    access_with_adjusted_size(addr, &data, size,
619821
+    access_with_adjusted_size(addr, &data, l,
619821
                               mr->ops->impl.min_access_size,
619821
                               mr->ops->impl.max_access_size,
619821
                               memory_region_read_accessor, mr);
619821
@@ -902,6 +935,8 @@ static void memory_region_dispatch_write(MemoryRegion *mr,
619821
                                          uint64_t data,
619821
                                          unsigned size)
619821
 {
619821
+    unsigned l;
619821
+
619821
     if (!memory_region_access_valid(mr, addr, size, true)) {
619821
         return; /* FIXME: better signalling */
619821
     }
619821
@@ -913,8 +948,9 @@ static void memory_region_dispatch_write(MemoryRegion *mr,
619821
         return;
619821
     }
619821
 
619821
+    l = memory_access_size(mr, size, addr);
619821
     /* FIXME: support unaligned access */
619821
-    access_with_adjusted_size(addr, &data, size,
619821
+    access_with_adjusted_size(addr, &data, l,
619821
                               mr->ops->impl.min_access_size,
619821
                               mr->ops->impl.max_access_size,
619821
                               memory_region_write_accessor, mr);
619821
-- 
619821
1.8.3.1
619821