Blame SOURCES/kvm-loader-Check-access-size-when-calling-rom_ptr-to-avo.patch

b38b0f
From 6dd1f60e226cb3c8ad0791dd6c8edba2493145cd Mon Sep 17 00:00:00 2001
b38b0f
From: Cornelia Huck <cohuck@redhat.com>
b38b0f
Date: Wed, 17 Apr 2019 13:57:19 +0100
b38b0f
Subject: [PATCH 02/24] loader: Check access size when calling rom_ptr() to
b38b0f
 avoid crashes
b38b0f
b38b0f
RH-Author: Cornelia Huck <cohuck@redhat.com>
b38b0f
Message-id: <20190417135741.25297-3-cohuck@redhat.com>
b38b0f
Patchwork-id: 85785
b38b0f
O-Subject: [RHEL-8.1.0 qemu-kvm PATCH v2 02/24] loader: Check access size when calling rom_ptr() to avoid crashes
b38b0f
Bugzilla: 1699070
b38b0f
RH-Acked-by: David Hildenbrand <david@redhat.com>
b38b0f
RH-Acked-by: Thomas Huth <thuth@redhat.com>
b38b0f
RH-Acked-by: Jens Freimann <jfreimann@redhat.com>
b38b0f
b38b0f
From: Thomas Huth <thuth@redhat.com>
b38b0f
b38b0f
The rom_ptr() function allows direct access to the ROM blobs that we
b38b0f
load during startup. However, there are currently no checks for the
b38b0f
size of the accesses, so it's currently possible to crash QEMU for
b38b0f
example with:
b38b0f
b38b0f
$ echo "Insane in the mainframe" > /tmp/test.txt
b38b0f
$ s390x-softmmu/qemu-system-s390x -kernel /tmp/test.txt -append xyz
b38b0f
Segmentation fault (core dumped)
b38b0f
$ s390x-softmmu/qemu-system-s390x -kernel /tmp/test.txt -initrd /tmp/test.txt
b38b0f
Segmentation fault (core dumped)
b38b0f
$ echo -n HdrS > /tmp/hdr.txt
b38b0f
$ sparc64-softmmu/qemu-system-sparc64 -kernel /tmp/hdr.txt -initrd /tmp/hdr.txt
b38b0f
Segmentation fault (core dumped)
b38b0f
b38b0f
We need a possibility to check the size of the ROM area that we want
b38b0f
to access, thus let's add a size parameter to the rom_ptr() function
b38b0f
to avoid these problems.
b38b0f
b38b0f
Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
b38b0f
Signed-off-by: Thomas Huth <thuth@redhat.com>
b38b0f
Message-Id: <1530005740-25254-1-git-send-email-thuth@redhat.com>
b38b0f
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
b38b0f
(cherry picked from commit 0f0f8b611eeea663c8d3b6021918033e257411a1)
b38b0f
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
b38b0f
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
b38b0f
---
b38b0f
 hw/core/loader.c     | 10 +++++-----
b38b0f
 hw/mips/mips_malta.c |  6 ++++--
b38b0f
 hw/s390x/ipl.c       | 18 ++++++++++++------
b38b0f
 hw/sparc/sun4m.c     |  4 ++--
b38b0f
 hw/sparc64/sun4u.c   |  4 ++--
b38b0f
 include/hw/loader.h  |  2 +-
b38b0f
 target/arm/cpu.c     |  2 +-
b38b0f
 7 files changed, 27 insertions(+), 19 deletions(-)
b38b0f
b38b0f
diff --git a/hw/core/loader.c b/hw/core/loader.c
b38b0f
index 06bdbca..bbb6e65 100644
b38b0f
--- a/hw/core/loader.c
b38b0f
+++ b/hw/core/loader.c
b38b0f
@@ -191,7 +191,7 @@ void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size,
b38b0f
         rom_add_blob_fixed(name, source, (nulp - source) + 1, dest);
b38b0f
     } else {
b38b0f
         rom_add_blob_fixed(name, source, buf_size, dest);
b38b0f
-        ptr = rom_ptr(dest + buf_size - 1);
b38b0f
+        ptr = rom_ptr(dest + buf_size - 1, sizeof(*ptr));
b38b0f
         *ptr = 0;
b38b0f
     }
b38b0f
 }
b38b0f
@@ -1165,7 +1165,7 @@ void rom_reset_order_override(void)
b38b0f
     fw_cfg_reset_order_override(fw_cfg);
b38b0f
 }
b38b0f
 
b38b0f
-static Rom *find_rom(hwaddr addr)
b38b0f
+static Rom *find_rom(hwaddr addr, size_t size)
b38b0f
 {
b38b0f
     Rom *rom;
b38b0f
 
b38b0f
@@ -1179,7 +1179,7 @@ static Rom *find_rom(hwaddr addr)
b38b0f
         if (rom->addr > addr) {
b38b0f
             continue;
b38b0f
         }
b38b0f
-        if (rom->addr + rom->romsize < addr) {
b38b0f
+        if (rom->addr + rom->romsize < addr + size) {
b38b0f
             continue;
b38b0f
         }
b38b0f
         return rom;
b38b0f
@@ -1249,11 +1249,11 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size)
b38b0f
     return (d + l) - dest;
b38b0f
 }
b38b0f
 
b38b0f
-void *rom_ptr(hwaddr addr)
b38b0f
+void *rom_ptr(hwaddr addr, size_t size)
b38b0f
 {
b38b0f
     Rom *rom;
b38b0f
 
b38b0f
-    rom = find_rom(addr);
b38b0f
+    rom = find_rom(addr, size);
b38b0f
     if (!rom || !rom->data)
b38b0f
         return NULL;
b38b0f
     return rom->data + (addr - rom->addr);
b38b0f
diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c
b38b0f
index f6513a4..8bbea0b 100644
b38b0f
--- a/hw/mips/mips_malta.c
b38b0f
+++ b/hw/mips/mips_malta.c
b38b0f
@@ -1139,11 +1139,13 @@ void mips_malta_init(MachineState *machine)
b38b0f
            a neat trick which allows bi-endian firmware. */
b38b0f
 #ifndef TARGET_WORDS_BIGENDIAN
b38b0f
         {
b38b0f
-            uint32_t *end, *addr = rom_ptr(FLASH_ADDRESS);
b38b0f
+            uint32_t *end, *addr;
b38b0f
+            const size_t swapsize = MIN(bios_size, 0x3e0000);
b38b0f
+            addr = rom_ptr(FLASH_ADDRESS, swapsize);
b38b0f
             if (!addr) {
b38b0f
                 addr = memory_region_get_ram_ptr(bios);
b38b0f
             }
b38b0f
-            end = (void *)addr + MIN(bios_size, 0x3e0000);
b38b0f
+            end = (void *)addr + swapsize;
b38b0f
             while (addr < end) {
b38b0f
                 bswap32s(addr);
b38b0f
                 addr++;
b38b0f
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
b38b0f
index 617ac43..10038ec 100644
b38b0f
--- a/hw/s390x/ipl.c
b38b0f
+++ b/hw/s390x/ipl.c
b38b0f
@@ -32,7 +32,6 @@
b38b0f
 #define KERN_PARM_AREA                  0x010480UL
b38b0f
 #define INITRD_START                    0x800000UL
b38b0f
 #define INITRD_PARM_START               0x010408UL
b38b0f
-#define INITRD_PARM_SIZE                0x010410UL
b38b0f
 #define PARMFILE_START                  0x001000UL
b38b0f
 #define ZIPL_IMAGE_START                0x009000UL
b38b0f
 #define IPL_PSW_MASK                    (PSW_MASK_32 | PSW_MASK_64)
b38b0f
@@ -164,12 +163,12 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
b38b0f
                 goto error;
b38b0f
             }
b38b0f
             /* if this is Linux use KERN_IMAGE_START */
b38b0f
-            magic = rom_ptr(LINUX_MAGIC_ADDR);
b38b0f
+            magic = rom_ptr(LINUX_MAGIC_ADDR, 6);
b38b0f
             if (magic && !memcmp(magic, "S390EP", 6)) {
b38b0f
                 pentry = KERN_IMAGE_START;
b38b0f
             } else {
b38b0f
                 /* if not Linux load the address of the (short) IPL PSW */
b38b0f
-                ipl_psw = rom_ptr(4);
b38b0f
+                ipl_psw = rom_ptr(4, 4);
b38b0f
                 if (ipl_psw) {
b38b0f
                     pentry = be32_to_cpu(*ipl_psw) & 0x7fffffffUL;
b38b0f
                 } else {
b38b0f
@@ -185,9 +184,12 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
b38b0f
          * loader) and it won't work. For this case we force it to 0x10000, too.
b38b0f
          */
b38b0f
         if (pentry == KERN_IMAGE_START || pentry == 0x800) {
b38b0f
+            char *parm_area = rom_ptr(KERN_PARM_AREA, strlen(ipl->cmdline) + 1);
b38b0f
             ipl->start_addr = KERN_IMAGE_START;
b38b0f
             /* Overwrite parameters in the kernel image, which are "rom" */
b38b0f
-            strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
b38b0f
+            if (parm_area) {
b38b0f
+                strcpy(parm_area, ipl->cmdline);
b38b0f
+            }
b38b0f
         } else {
b38b0f
             ipl->start_addr = pentry;
b38b0f
         }
b38b0f
@@ -195,6 +197,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
b38b0f
         if (ipl->initrd) {
b38b0f
             ram_addr_t initrd_offset;
b38b0f
             int initrd_size;
b38b0f
+            uint64_t *romptr;
b38b0f
 
b38b0f
             initrd_offset = INITRD_START;
b38b0f
             while (kernel_size + 0x100000 > initrd_offset) {
b38b0f
@@ -211,8 +214,11 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
b38b0f
              * we have to overwrite values in the kernel image,
b38b0f
              * which are "rom"
b38b0f
              */
b38b0f
-            stq_p(rom_ptr(INITRD_PARM_START), initrd_offset);
b38b0f
-            stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size);
b38b0f
+            romptr = rom_ptr(INITRD_PARM_START, 16);
b38b0f
+            if (romptr) {
b38b0f
+                stq_p(romptr, initrd_offset);
b38b0f
+                stq_p(romptr + 1, initrd_size);
b38b0f
+            }
b38b0f
         }
b38b0f
     }
b38b0f
     /*
b38b0f
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
b38b0f
index 6471aca..a400442 100644
b38b0f
--- a/hw/sparc/sun4m.c
b38b0f
+++ b/hw/sparc/sun4m.c
b38b0f
@@ -272,8 +272,8 @@ static unsigned long sun4m_load_kernel(const char *kernel_filename,
b38b0f
         }
b38b0f
         if (initrd_size > 0) {
b38b0f
             for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
b38b0f
-                ptr = rom_ptr(KERNEL_LOAD_ADDR + i);
b38b0f
-                if (ldl_p(ptr) == 0x48647253) { // HdrS
b38b0f
+                ptr = rom_ptr(KERNEL_LOAD_ADDR + i, 24);
b38b0f
+                if (ptr && ldl_p(ptr) == 0x48647253) { /* HdrS */
b38b0f
                     stl_p(ptr + 16, INITRD_LOAD_ADDR);
b38b0f
                     stl_p(ptr + 20, initrd_size);
b38b0f
                     break;
b38b0f
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
b38b0f
index 2044a52..1410c3a 100644
b38b0f
--- a/hw/sparc64/sun4u.c
b38b0f
+++ b/hw/sparc64/sun4u.c
b38b0f
@@ -186,8 +186,8 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename,
b38b0f
         }
b38b0f
         if (*initrd_size > 0) {
b38b0f
             for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
b38b0f
-                ptr = rom_ptr(*kernel_addr + i);
b38b0f
-                if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */
b38b0f
+                ptr = rom_ptr(*kernel_addr + i, 32);
b38b0f
+                if (ptr && ldl_p(ptr + 8) == 0x48647253) { /* HdrS */
b38b0f
                     stl_p(ptr + 24, *initrd_addr + *kernel_addr);
b38b0f
                     stl_p(ptr + 28, *initrd_size);
b38b0f
                     break;
b38b0f
diff --git a/include/hw/loader.h b/include/hw/loader.h
b38b0f
index 5ed3fd8..e98b84b 100644
b38b0f
--- a/include/hw/loader.h
b38b0f
+++ b/include/hw/loader.h
b38b0f
@@ -226,7 +226,7 @@ void rom_set_fw(FWCfgState *f);
b38b0f
 void rom_set_order_override(int order);
b38b0f
 void rom_reset_order_override(void);
b38b0f
 int rom_copy(uint8_t *dest, hwaddr addr, size_t size);
b38b0f
-void *rom_ptr(hwaddr addr);
b38b0f
+void *rom_ptr(hwaddr addr, size_t size);
b38b0f
 void hmp_info_roms(Monitor *mon, const QDict *qdict);
b38b0f
 
b38b0f
 #define rom_add_file_fixed(_f, _a, _i)          \
b38b0f
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
b38b0f
index 9d030e0..6773f40 100644
b38b0f
--- a/target/arm/cpu.c
b38b0f
+++ b/target/arm/cpu.c
b38b0f
@@ -219,7 +219,7 @@ static void arm_cpu_reset(CPUState *s)
b38b0f
 
b38b0f
         /* Load the initial SP and PC from offset 0 and 4 in the vector table */
b38b0f
         vecbase = env->v7m.vecbase[env->v7m.secure];
b38b0f
-        rom = rom_ptr(vecbase);
b38b0f
+        rom = rom_ptr(vecbase, 8);
b38b0f
         if (rom) {
b38b0f
             /* Address zero is covered by ROM which hasn't yet been
b38b0f
              * copied into physical memory.
b38b0f
-- 
b38b0f
1.8.3.1
b38b0f