loader: Check access size when calling rom_ptr() to avoid crashes
The rom_ptr() function allows direct access to the ROM blobs that we load during startup. However, there are currently no checks for the size of the accesses, so it's currently possible to crash QEMU for example with: $ echo "Insane in the mainframe" > /tmp/test.txt $ s390x-softmmu/qemu-system-s390x -kernel /tmp/test.txt -append xyz Segmentation fault (core dumped) $ s390x-softmmu/qemu-system-s390x -kernel /tmp/test.txt -initrd /tmp/test.txt Segmentation fault (core dumped) $ echo -n HdrS > /tmp/hdr.txt $ sparc64-softmmu/qemu-system-sparc64 -kernel /tmp/hdr.txt -initrd /tmp/hdr.txt Segmentation fault (core dumped) We need a possibility to check the size of the ROM area that we want to access, thus let's add a size parameter to the rom_ptr() function to avoid these problems. Acked-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Thomas Huth <thuth@redhat.com> Message-Id: <1530005740-25254-1-git-send-email-thuth@redhat.com> Signed-off-by: Cornelia Huck <cohuck@redhat.com>
This commit is contained in:
parent
76ed4b18de
commit
0f0f8b611e
|
@ -191,7 +191,7 @@ void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size,
|
||||||
rom_add_blob_fixed(name, source, (nulp - source) + 1, dest);
|
rom_add_blob_fixed(name, source, (nulp - source) + 1, dest);
|
||||||
} else {
|
} else {
|
||||||
rom_add_blob_fixed(name, source, buf_size, dest);
|
rom_add_blob_fixed(name, source, buf_size, dest);
|
||||||
ptr = rom_ptr(dest + buf_size - 1);
|
ptr = rom_ptr(dest + buf_size - 1, sizeof(*ptr));
|
||||||
*ptr = 0;
|
*ptr = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1165,7 +1165,7 @@ void rom_reset_order_override(void)
|
||||||
fw_cfg_reset_order_override(fw_cfg);
|
fw_cfg_reset_order_override(fw_cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Rom *find_rom(hwaddr addr)
|
static Rom *find_rom(hwaddr addr, size_t size)
|
||||||
{
|
{
|
||||||
Rom *rom;
|
Rom *rom;
|
||||||
|
|
||||||
|
@ -1179,7 +1179,7 @@ static Rom *find_rom(hwaddr addr)
|
||||||
if (rom->addr > addr) {
|
if (rom->addr > addr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (rom->addr + rom->romsize < addr) {
|
if (rom->addr + rom->romsize < addr + size) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return rom;
|
return rom;
|
||||||
|
@ -1249,11 +1249,11 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size)
|
||||||
return (d + l) - dest;
|
return (d + l) - dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *rom_ptr(hwaddr addr)
|
void *rom_ptr(hwaddr addr, size_t size)
|
||||||
{
|
{
|
||||||
Rom *rom;
|
Rom *rom;
|
||||||
|
|
||||||
rom = find_rom(addr);
|
rom = find_rom(addr, size);
|
||||||
if (!rom || !rom->data)
|
if (!rom || !rom->data)
|
||||||
return NULL;
|
return NULL;
|
||||||
return rom->data + (addr - rom->addr);
|
return rom->data + (addr - rom->addr);
|
||||||
|
|
|
@ -1133,11 +1133,13 @@ void mips_malta_init(MachineState *machine)
|
||||||
a neat trick which allows bi-endian firmware. */
|
a neat trick which allows bi-endian firmware. */
|
||||||
#ifndef TARGET_WORDS_BIGENDIAN
|
#ifndef TARGET_WORDS_BIGENDIAN
|
||||||
{
|
{
|
||||||
uint32_t *end, *addr = rom_ptr(FLASH_ADDRESS);
|
uint32_t *end, *addr;
|
||||||
|
const size_t swapsize = MIN(bios_size, 0x3e0000);
|
||||||
|
addr = rom_ptr(FLASH_ADDRESS, swapsize);
|
||||||
if (!addr) {
|
if (!addr) {
|
||||||
addr = memory_region_get_ram_ptr(bios);
|
addr = memory_region_get_ram_ptr(bios);
|
||||||
}
|
}
|
||||||
end = (void *)addr + MIN(bios_size, 0x3e0000);
|
end = (void *)addr + swapsize;
|
||||||
while (addr < end) {
|
while (addr < end) {
|
||||||
bswap32s(addr);
|
bswap32s(addr);
|
||||||
addr++;
|
addr++;
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
#define KERN_PARM_AREA 0x010480UL
|
#define KERN_PARM_AREA 0x010480UL
|
||||||
#define INITRD_START 0x800000UL
|
#define INITRD_START 0x800000UL
|
||||||
#define INITRD_PARM_START 0x010408UL
|
#define INITRD_PARM_START 0x010408UL
|
||||||
#define INITRD_PARM_SIZE 0x010410UL
|
|
||||||
#define PARMFILE_START 0x001000UL
|
#define PARMFILE_START 0x001000UL
|
||||||
#define ZIPL_IMAGE_START 0x009000UL
|
#define ZIPL_IMAGE_START 0x009000UL
|
||||||
#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
|
#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
|
||||||
|
@ -165,12 +164,12 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
/* if this is Linux use KERN_IMAGE_START */
|
/* if this is Linux use KERN_IMAGE_START */
|
||||||
magic = rom_ptr(LINUX_MAGIC_ADDR);
|
magic = rom_ptr(LINUX_MAGIC_ADDR, 6);
|
||||||
if (magic && !memcmp(magic, "S390EP", 6)) {
|
if (magic && !memcmp(magic, "S390EP", 6)) {
|
||||||
pentry = KERN_IMAGE_START;
|
pentry = KERN_IMAGE_START;
|
||||||
} else {
|
} else {
|
||||||
/* if not Linux load the address of the (short) IPL PSW */
|
/* if not Linux load the address of the (short) IPL PSW */
|
||||||
ipl_psw = rom_ptr(4);
|
ipl_psw = rom_ptr(4, 4);
|
||||||
if (ipl_psw) {
|
if (ipl_psw) {
|
||||||
pentry = be32_to_cpu(*ipl_psw) & 0x7fffffffUL;
|
pentry = be32_to_cpu(*ipl_psw) & 0x7fffffffUL;
|
||||||
} else {
|
} else {
|
||||||
|
@ -186,9 +185,12 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
||||||
* loader) and it won't work. For this case we force it to 0x10000, too.
|
* loader) and it won't work. For this case we force it to 0x10000, too.
|
||||||
*/
|
*/
|
||||||
if (pentry == KERN_IMAGE_START || pentry == 0x800) {
|
if (pentry == KERN_IMAGE_START || pentry == 0x800) {
|
||||||
|
char *parm_area = rom_ptr(KERN_PARM_AREA, strlen(ipl->cmdline) + 1);
|
||||||
ipl->start_addr = KERN_IMAGE_START;
|
ipl->start_addr = KERN_IMAGE_START;
|
||||||
/* Overwrite parameters in the kernel image, which are "rom" */
|
/* Overwrite parameters in the kernel image, which are "rom" */
|
||||||
strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
|
if (parm_area) {
|
||||||
|
strcpy(parm_area, ipl->cmdline);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ipl->start_addr = pentry;
|
ipl->start_addr = pentry;
|
||||||
}
|
}
|
||||||
|
@ -196,6 +198,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
||||||
if (ipl->initrd) {
|
if (ipl->initrd) {
|
||||||
ram_addr_t initrd_offset;
|
ram_addr_t initrd_offset;
|
||||||
int initrd_size;
|
int initrd_size;
|
||||||
|
uint64_t *romptr;
|
||||||
|
|
||||||
initrd_offset = INITRD_START;
|
initrd_offset = INITRD_START;
|
||||||
while (kernel_size + 0x100000 > initrd_offset) {
|
while (kernel_size + 0x100000 > initrd_offset) {
|
||||||
|
@ -212,8 +215,11 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
||||||
* we have to overwrite values in the kernel image,
|
* we have to overwrite values in the kernel image,
|
||||||
* which are "rom"
|
* which are "rom"
|
||||||
*/
|
*/
|
||||||
stq_p(rom_ptr(INITRD_PARM_START), initrd_offset);
|
romptr = rom_ptr(INITRD_PARM_START, 16);
|
||||||
stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size);
|
if (romptr) {
|
||||||
|
stq_p(romptr, initrd_offset);
|
||||||
|
stq_p(romptr + 1, initrd_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -272,8 +272,8 @@ static unsigned long sun4m_load_kernel(const char *kernel_filename,
|
||||||
}
|
}
|
||||||
if (initrd_size > 0) {
|
if (initrd_size > 0) {
|
||||||
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
|
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
|
||||||
ptr = rom_ptr(KERNEL_LOAD_ADDR + i);
|
ptr = rom_ptr(KERNEL_LOAD_ADDR + i, 24);
|
||||||
if (ldl_p(ptr) == 0x48647253) { // HdrS
|
if (ptr && ldl_p(ptr) == 0x48647253) { /* HdrS */
|
||||||
stl_p(ptr + 16, INITRD_LOAD_ADDR);
|
stl_p(ptr + 16, INITRD_LOAD_ADDR);
|
||||||
stl_p(ptr + 20, initrd_size);
|
stl_p(ptr + 20, initrd_size);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -186,8 +186,8 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename,
|
||||||
}
|
}
|
||||||
if (*initrd_size > 0) {
|
if (*initrd_size > 0) {
|
||||||
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
|
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
|
||||||
ptr = rom_ptr(*kernel_addr + i);
|
ptr = rom_ptr(*kernel_addr + i, 32);
|
||||||
if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */
|
if (ptr && ldl_p(ptr + 8) == 0x48647253) { /* HdrS */
|
||||||
stl_p(ptr + 24, *initrd_addr + *kernel_addr);
|
stl_p(ptr + 24, *initrd_addr + *kernel_addr);
|
||||||
stl_p(ptr + 28, *initrd_size);
|
stl_p(ptr + 28, *initrd_size);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -226,7 +226,7 @@ void rom_set_fw(FWCfgState *f);
|
||||||
void rom_set_order_override(int order);
|
void rom_set_order_override(int order);
|
||||||
void rom_reset_order_override(void);
|
void rom_reset_order_override(void);
|
||||||
int rom_copy(uint8_t *dest, hwaddr addr, size_t size);
|
int rom_copy(uint8_t *dest, hwaddr addr, size_t size);
|
||||||
void *rom_ptr(hwaddr addr);
|
void *rom_ptr(hwaddr addr, size_t size);
|
||||||
void hmp_info_roms(Monitor *mon, const QDict *qdict);
|
void hmp_info_roms(Monitor *mon, const QDict *qdict);
|
||||||
|
|
||||||
#define rom_add_file_fixed(_f, _a, _i) \
|
#define rom_add_file_fixed(_f, _a, _i) \
|
||||||
|
|
|
@ -239,7 +239,7 @@ static void arm_cpu_reset(CPUState *s)
|
||||||
|
|
||||||
/* Load the initial SP and PC from offset 0 and 4 in the vector table */
|
/* Load the initial SP and PC from offset 0 and 4 in the vector table */
|
||||||
vecbase = env->v7m.vecbase[env->v7m.secure];
|
vecbase = env->v7m.vecbase[env->v7m.secure];
|
||||||
rom = rom_ptr(vecbase);
|
rom = rom_ptr(vecbase, 8);
|
||||||
if (rom) {
|
if (rom) {
|
||||||
/* Address zero is covered by ROM which hasn't yet been
|
/* Address zero is covered by ROM which hasn't yet been
|
||||||
* copied into physical memory.
|
* copied into physical memory.
|
||||||
|
|
Loading…
Reference in a new issue