yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone

Blame SOURCES/kvm-nvram-Exit-QEMU-if-NVRAM-cannot-contain-all-prom-env.patch

f66865
From aac48d07764ce73c2ba23e3f05ccd29db190024a Mon Sep 17 00:00:00 2001
f66865
From: Greg Kurz <gkurz@redhat.com>
f66865
Date: Thu, 8 Oct 2020 11:06:43 -0400
f66865
Subject: [PATCH 04/14] nvram: Exit QEMU if NVRAM cannot contain all -prom-env
f66865
 data
f66865
f66865
RH-Author: Greg Kurz <gkurz@redhat.com>
f66865
Message-id: <20201008110643.155902-2-gkurz@redhat.com>
f66865
Patchwork-id: 98577
f66865
O-Subject: [RHEL-8.4.0 qemu-kvm PATCH 1/1] nvram: Exit QEMU if NVRAM cannot contain all -prom-env data
f66865
Bugzilla: 1874780
f66865
RH-Acked-by: David Gibson <dgibson@redhat.com>
f66865
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
f66865
RH-Acked-by: Thomas Huth <thuth@redhat.com>
f66865
f66865
From: Greg Kurz <groug@kaod.org>
f66865
f66865
Since commit 61f20b9dc5b7 ("spapr_nvram: Pre-initialize the NVRAM to
f66865
support the -prom-env parameter"), pseries machines can pre-initialize
f66865
the "system" partition in the NVRAM with the data passed to all -prom-env
f66865
parameters on the QEMU command line.
f66865
f66865
In this case it is assumed that all the data fits in 64 KiB, but the user
f66865
can easily pass more and crash QEMU:
f66865
f66865
$ qemu-system-ppc64 -M pseries $(for ((x=0;x<128;x++)); do \
f66865
  echo -n " -prom-env " ; printf "%0.sx" {1..1024}; \
f66865
  done) # this requires ~128 Kib
f66865
malloc(): corrupted top size
f66865
Aborted (core dumped)
f66865
f66865
This happens because we don't check if all the prom-env data fits in
f66865
the NVRAM and chrp_nvram_set_var() happily memcpy() it passed the
f66865
buffer.
f66865
f66865
This crash affects basically all ppc/ppc64 machine types that use -prom-env:
f66865
- pseries (all versions)
f66865
- g3beige
f66865
- mac99
f66865
f66865
and also sparc/sparc64 machine types:
f66865
- LX
f66865
- SPARCClassic
f66865
- SPARCbook
f66865
- SS-10
f66865
- SS-20
f66865
- SS-4
f66865
- SS-5
f66865
- SS-600MP
f66865
- Voyager
f66865
- sun4u
f66865
- sun4v
f66865
f66865
Add a max_len argument to chrp_nvram_create_system_partition() so that
f66865
it can check the available size before writing to memory.
f66865
f66865
Since NVRAM is populated at machine init, it seems reasonable to consider
f66865
this error as fatal. So, instead of reporting an error when we detect that
f66865
the NVRAM is too small and adapt all machine types to handle it, we simply
f66865
exit QEMU in all cases. This is still better than crashing. If someone
f66865
wants another behavior, I guess this can be reworked later.
f66865
f66865
Tested with:
f66865
f66865
$ yes q | \
f66865
  (for arch in ppc ppc64 sparc sparc64; do \
f66865
       echo == $arch ==; \
f66865
       qemu=${arch}-softmmu/qemu-system-$arch; \
f66865
       for mach in $($qemu -M help | awk '! /^Supported/ { print $1 }'); do \
f66865
           echo $mach; \
f66865
           $qemu -M $mach -monitor stdio -nodefaults -nographic \
f66865
           $(for ((x=0;x<128;x++)); do \
f66865
                 echo -n " -prom-env " ; printf "%0.sx" {1..1024}; \
f66865
             done) >/dev/null; \
f66865
        done; echo; \
f66865
   done)
f66865
f66865
Without the patch, affected machine types cause QEMU to report some
f66865
memory corruption and crash:
f66865
f66865
malloc(): corrupted top size
f66865
f66865
free(): invalid size
f66865
f66865
*** stack smashing detected ***: terminated
f66865
f66865
With the patch, QEMU prints the following message and exits:
f66865
f66865
NVRAM is too small. Try to pass less data to -prom-env
f66865
f66865
It seems that the conditions for the crash have always existed, but it
f66865
affects pseries, the machine type I care for, since commit 61f20b9dc5b7
f66865
only.
f66865
f66865
Fixes: 61f20b9dc5b7 ("spapr_nvram: Pre-initialize the NVRAM to support the -prom-env parameter")
f66865
RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1867739
f66865
Reported-by: John Snow <jsnow@redhat.com>
f66865
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
f66865
Signed-off-by: Greg Kurz <groug@kaod.org>
f66865
Message-Id: <159736033937.350502.12402444542194031035.stgit@bahia.lan>
f66865
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
f66865
(cherry picked from commit 37035df51eaabb8d26b71da75b88a1c6727de8fa)
f66865
Signed-off-by: Greg Kurz <gkurz@redhat.com>
f66865
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
f66865
---
f66865
 hw/nvram/chrp_nvram.c         | 24 +++++++++++++++++++++---
f66865
 hw/nvram/mac_nvram.c          |  2 +-
f66865
 hw/nvram/spapr_nvram.c        |  3 ++-
f66865
 hw/sparc/sun4m.c              |  2 +-
f66865
 hw/sparc64/sun4u.c            |  2 +-
f66865
 include/hw/nvram/chrp_nvram.h |  3 ++-
f66865
 6 files changed, 28 insertions(+), 8 deletions(-)
f66865
f66865
diff --git a/hw/nvram/chrp_nvram.c b/hw/nvram/chrp_nvram.c
f66865
index d969f26704..d4d10a7c03 100644
f66865
--- a/hw/nvram/chrp_nvram.c
f66865
+++ b/hw/nvram/chrp_nvram.c
f66865
@@ -21,14 +21,21 @@
f66865
 
f66865
 #include "qemu/osdep.h"
f66865
 #include "qemu/cutils.h"
f66865
+#include "qemu/error-report.h"
f66865
 #include "hw/nvram/chrp_nvram.h"
f66865
 #include "sysemu/sysemu.h"
f66865
 
f66865
-static int chrp_nvram_set_var(uint8_t *nvram, int addr, const char *str)
f66865
+static int chrp_nvram_set_var(uint8_t *nvram, int addr, const char *str,
f66865
+                              int max_len)
f66865
 {
f66865
     int len;
f66865
 
f66865
     len = strlen(str) + 1;
f66865
+
f66865
+    if (max_len < len) {
f66865
+        return -1;
f66865
+    }
f66865
+
f66865
     memcpy(&nvram[addr], str, len);
f66865
 
f66865
     return addr + len;
f66865
@@ -38,19 +45,26 @@ static int chrp_nvram_set_var(uint8_t *nvram, int addr, const char *str)
f66865
  * Create a "system partition", used for the Open Firmware
f66865
  * environment variables.
f66865
  */
f66865
-int chrp_nvram_create_system_partition(uint8_t *data, int min_len)
f66865
+int chrp_nvram_create_system_partition(uint8_t *data, int min_len, int max_len)
f66865
 {
f66865
     ChrpNvramPartHdr *part_header;
f66865
     unsigned int i;
f66865
     int end;
f66865
 
f66865
+    if (max_len < sizeof(*part_header)) {
f66865
+        goto fail;
f66865
+    }
f66865
+
f66865
     part_header = (ChrpNvramPartHdr *)data;
f66865
     part_header->signature = CHRP_NVPART_SYSTEM;
f66865
     pstrcpy(part_header->name, sizeof(part_header->name), "system");
f66865
 
f66865
     end = sizeof(ChrpNvramPartHdr);
f66865
     for (i = 0; i < nb_prom_envs; i++) {
f66865
-        end = chrp_nvram_set_var(data, end, prom_envs[i]);
f66865
+        end = chrp_nvram_set_var(data, end, prom_envs[i], max_len - end);
f66865
+        if (end == -1) {
f66865
+            goto fail;
f66865
+        }
f66865
     }
f66865
 
f66865
     /* End marker */
f66865
@@ -65,6 +79,10 @@ int chrp_nvram_create_system_partition(uint8_t *data, int min_len)
f66865
     chrp_nvram_finish_partition(part_header, end);
f66865
 
f66865
     return end;
f66865
+
f66865
+fail:
f66865
+    error_report("NVRAM is too small. Try to pass less data to -prom-env");
f66865
+    exit(EXIT_FAILURE);
f66865
 }
f66865
 
f66865
 /**
f66865
diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c
f66865
index 9a47e35b8e..ecfb36182f 100644
f66865
--- a/hw/nvram/mac_nvram.c
f66865
+++ b/hw/nvram/mac_nvram.c
f66865
@@ -152,7 +152,7 @@ static void pmac_format_nvram_partition_of(MacIONVRAMState *nvr, int off,
f66865
 
f66865
     /* OpenBIOS nvram variables partition */
f66865
     sysp_end = chrp_nvram_create_system_partition(&nvr->data[off],
f66865
-                                                  DEF_SYSTEM_SIZE) + off;
f66865
+                                                  DEF_SYSTEM_SIZE, len) + off;
f66865
 
f66865
     /* Free space partition */
f66865
     chrp_nvram_create_free_partition(&nvr->data[sysp_end], len - sysp_end);
f66865
diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c
f66865
index 838082b451..225cd69b49 100644
f66865
--- a/hw/nvram/spapr_nvram.c
f66865
+++ b/hw/nvram/spapr_nvram.c
f66865
@@ -188,7 +188,8 @@ static void spapr_nvram_realize(SpaprVioDevice *dev, Error **errp)
f66865
         }
f66865
     } else if (nb_prom_envs > 0) {
f66865
         /* Create a system partition to pass the -prom-env variables */
f66865
-        chrp_nvram_create_system_partition(nvram->buf, MIN_NVRAM_SIZE / 4);
f66865
+        chrp_nvram_create_system_partition(nvram->buf, MIN_NVRAM_SIZE / 4,
f66865
+                                           nvram->size);
f66865
         chrp_nvram_create_free_partition(&nvram->buf[MIN_NVRAM_SIZE / 4],
f66865
                                          nvram->size - MIN_NVRAM_SIZE / 4);
f66865
     }
f66865
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
f66865
index 2aaa5bf1ae..cf2d0762d9 100644
f66865
--- a/hw/sparc/sun4m.c
f66865
+++ b/hw/sparc/sun4m.c
f66865
@@ -142,7 +142,7 @@ static void nvram_init(Nvram *nvram, uint8_t *macaddr,
f66865
     memset(image, '\0', sizeof(image));
f66865
 
f66865
     /* OpenBIOS nvram variables partition */
f66865
-    sysp_end = chrp_nvram_create_system_partition(image, 0);
f66865
+    sysp_end = chrp_nvram_create_system_partition(image, 0, 0x1fd0);
f66865
 
f66865
     /* Free space partition */
f66865
     chrp_nvram_create_free_partition(&image[sysp_end], 0x1fd0 - sysp_end);
f66865
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
f66865
index 955082773b..f5295a687e 100644
f66865
--- a/hw/sparc64/sun4u.c
f66865
+++ b/hw/sparc64/sun4u.c
f66865
@@ -137,7 +137,7 @@ static int sun4u_NVRAM_set_params(Nvram *nvram, uint16_t NVRAM_size,
f66865
     memset(image, '\0', sizeof(image));
f66865
 
f66865
     /* OpenBIOS nvram variables partition */
f66865
-    sysp_end = chrp_nvram_create_system_partition(image, 0);
f66865
+    sysp_end = chrp_nvram_create_system_partition(image, 0, 0x1fd0);
f66865
 
f66865
     /* Free space partition */
f66865
     chrp_nvram_create_free_partition(&image[sysp_end], 0x1fd0 - sysp_end);
f66865
diff --git a/include/hw/nvram/chrp_nvram.h b/include/hw/nvram/chrp_nvram.h
f66865
index 09941a9be4..4a0f5c21b8 100644
f66865
--- a/include/hw/nvram/chrp_nvram.h
f66865
+++ b/include/hw/nvram/chrp_nvram.h
f66865
@@ -50,7 +50,8 @@ chrp_nvram_finish_partition(ChrpNvramPartHdr *header, uint32_t size)
f66865
     header->checksum = sum & 0xff;
f66865
 }
f66865
 
f66865
-int chrp_nvram_create_system_partition(uint8_t *data, int min_len);
f66865
+/* chrp_nvram_create_system_partition() failure is fatal */
f66865
+int chrp_nvram_create_system_partition(uint8_t *data, int min_len, int max_len);
f66865
 int chrp_nvram_create_free_partition(uint8_t *data, int len);
f66865
 
f66865
 #endif
f66865
-- 
f66865
2.27.0
f66865