37035df51e
Since commit61f20b9dc5
("spapr_nvram: Pre-initialize the NVRAM to support the -prom-env parameter"), pseries machines can pre-initialize the "system" partition in the NVRAM with the data passed to all -prom-env parameters on the QEMU command line. In this case it is assumed that all the data fits in 64 KiB, but the user can easily pass more and crash QEMU: $ qemu-system-ppc64 -M pseries $(for ((x=0;x<128;x++)); do \ echo -n " -prom-env " ; printf "%0.sx" {1..1024}; \ done) # this requires ~128 Kib malloc(): corrupted top size Aborted (core dumped) This happens because we don't check if all the prom-env data fits in the NVRAM and chrp_nvram_set_var() happily memcpy() it passed the buffer. This crash affects basically all ppc/ppc64 machine types that use -prom-env: - pseries (all versions) - g3beige - mac99 and also sparc/sparc64 machine types: - LX - SPARCClassic - SPARCbook - SS-10 - SS-20 - SS-4 - SS-5 - SS-600MP - Voyager - sun4u - sun4v Add a max_len argument to chrp_nvram_create_system_partition() so that it can check the available size before writing to memory. Since NVRAM is populated at machine init, it seems reasonable to consider this error as fatal. So, instead of reporting an error when we detect that the NVRAM is too small and adapt all machine types to handle it, we simply exit QEMU in all cases. This is still better than crashing. If someone wants another behavior, I guess this can be reworked later. Tested with: $ yes q | \ (for arch in ppc ppc64 sparc sparc64; do \ echo == $arch ==; \ qemu=${arch}-softmmu/qemu-system-$arch; \ for mach in $($qemu -M help | awk '! /^Supported/ { print $1 }'); do \ echo $mach; \ $qemu -M $mach -monitor stdio -nodefaults -nographic \ $(for ((x=0;x<128;x++)); do \ echo -n " -prom-env " ; printf "%0.sx" {1..1024}; \ done) >/dev/null; \ done; echo; \ done) Without the patch, affected machine types cause QEMU to report some memory corruption and crash: malloc(): corrupted top size free(): invalid size *** stack smashing detected ***: terminated With the patch, QEMU prints the following message and exits: NVRAM is too small. Try to pass less data to -prom-env It seems that the conditions for the crash have always existed, but it affects pseries, the machine type I care for, since commit61f20b9dc5
only. Fixes:61f20b9dc5
("spapr_nvram: Pre-initialize the NVRAM to support the -prom-env parameter") RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1867739 Reported-by: John Snow <jsnow@redhat.com> Reviewed-by: Laurent Vivier <laurent@vivier.eu> Signed-off-by: Greg Kurz <groug@kaod.org> Message-Id: <159736033937.350502.12402444542194031035.stgit@bahia.lan> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
103 lines
2.7 KiB
C
103 lines
2.7 KiB
C
/*
|
|
* Common Hardware Reference Platform NVRAM helper functions.
|
|
*
|
|
* The CHRP NVRAM layout is used by OpenBIOS and SLOF. See CHRP
|
|
* specification, chapter 8, or the LoPAPR specification for details
|
|
* about the NVRAM layout.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published
|
|
* by the Free Software Foundation; either version 2 of the License,
|
|
* or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "qemu/cutils.h"
|
|
#include "qemu/error-report.h"
|
|
#include "hw/nvram/chrp_nvram.h"
|
|
#include "sysemu/sysemu.h"
|
|
|
|
static int chrp_nvram_set_var(uint8_t *nvram, int addr, const char *str,
|
|
int max_len)
|
|
{
|
|
int len;
|
|
|
|
len = strlen(str) + 1;
|
|
|
|
if (max_len < len) {
|
|
return -1;
|
|
}
|
|
|
|
memcpy(&nvram[addr], str, len);
|
|
|
|
return addr + len;
|
|
}
|
|
|
|
/**
|
|
* Create a "system partition", used for the Open Firmware
|
|
* environment variables.
|
|
*/
|
|
int chrp_nvram_create_system_partition(uint8_t *data, int min_len, int max_len)
|
|
{
|
|
ChrpNvramPartHdr *part_header;
|
|
unsigned int i;
|
|
int end;
|
|
|
|
if (max_len < sizeof(*part_header)) {
|
|
goto fail;
|
|
}
|
|
|
|
part_header = (ChrpNvramPartHdr *)data;
|
|
part_header->signature = CHRP_NVPART_SYSTEM;
|
|
pstrcpy(part_header->name, sizeof(part_header->name), "system");
|
|
|
|
end = sizeof(ChrpNvramPartHdr);
|
|
for (i = 0; i < nb_prom_envs; i++) {
|
|
end = chrp_nvram_set_var(data, end, prom_envs[i], max_len - end);
|
|
if (end == -1) {
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
/* End marker */
|
|
data[end++] = '\0';
|
|
|
|
end = (end + 15) & ~15;
|
|
/* XXX: OpenBIOS is not able to grow up a partition. Leave some space for
|
|
new variables. */
|
|
if (end < min_len) {
|
|
end = min_len;
|
|
}
|
|
chrp_nvram_finish_partition(part_header, end);
|
|
|
|
return end;
|
|
|
|
fail:
|
|
error_report("NVRAM is too small. Try to pass less data to -prom-env");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/**
|
|
* Create a "free space" partition
|
|
*/
|
|
int chrp_nvram_create_free_partition(uint8_t *data, int len)
|
|
{
|
|
ChrpNvramPartHdr *part_header;
|
|
|
|
part_header = (ChrpNvramPartHdr *)data;
|
|
part_header->signature = CHRP_NVPART_FREE;
|
|
pstrcpy(part_header->name, sizeof(part_header->name), "free");
|
|
|
|
chrp_nvram_finish_partition(part_header, len);
|
|
|
|
return len;
|
|
}
|