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

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