mirror of https://github.com/wolfSSL/wolfBoot.git
F-4711: bound e820 entries to prevent boot_params stack overflow
e820_add_entry_cb() appended every FSP-supplied resource descriptor into boot_params->e820_table[] with no check against E820_MAX_ENTRIES_ZEROPAGE (128). A HOB list with more than 128 EFI_HOB_TYPE_RESOURCE_DESCRIPTOR entries therefore wrote FSP-controlled addr/size/type triples past the fixed-size table into the stack-allocated boot_params in load_linux(), corrupting adjacent fields and the saved return address. Reject any entry once the table is full (return non-zero, which aborts the HOB iteration). e820_entries stays uint8_t since it is a fixed-offset field in the Linux zero-page layout and the cap makes the 256 wrap unreachable. Add unit-linux-loader-e820 regression test (x86 32bit, standalone) that feeds 200 descriptors and asserts the table never overflows.pull/788/head
parent
277e8013cc
commit
a8a9eec96b
|
|
@ -73,8 +73,12 @@ static int e820_add_entry_cb(uint64_t start, uint64_t length, uint32_t type,
|
|||
void *ctx)
|
||||
{
|
||||
struct boot_params *bp = (struct boot_params*)ctx;
|
||||
struct boot_e820_entry *map = bp->e820_table + bp->e820_entries;
|
||||
struct boot_e820_entry *map;
|
||||
|
||||
if (bp->e820_entries >= E820_MAX_ENTRIES_ZEROPAGE)
|
||||
return -1;
|
||||
|
||||
map = bp->e820_table + bp->e820_entries;
|
||||
map->addr = start;
|
||||
map->size = length;
|
||||
map->type = (type == EFI_RESOURCE_SYSTEM_MEMORY) ? E820_TYPE_RAM :
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ TESTS:=unit-parser unit-fdt unit-extflash unit-string unit-spi-flash unit-aes128
|
|||
TESTS+=unit-tpm-check-rot-auth
|
||||
TESTS+=unit-tpm-api-names
|
||||
TESTS+=unit-fit-gzip unit-fit-nogzip
|
||||
TESTS+=unit-linux-loader-e820
|
||||
|
||||
include unit-sign-encrypted-output.mkfrag
|
||||
|
||||
|
|
@ -264,6 +265,13 @@ unit-chacha20: ../../include/target.h unit-extflash.c
|
|||
unit-pci: unit-pci.c ../../src/pci.c
|
||||
gcc -o $@ $< $(CFLAGS) -DWOLFBOOT_USE_PCI $(LDFLAGS)
|
||||
|
||||
# linux_loader.c is x86 32bit only and pulls in inline asm guarded on 32bit;
|
||||
# build standalone with -m32 and without coverage (no 32bit gcov/check libs).
|
||||
unit-linux-loader-e820: ../../include/target.h unit-linux-loader-e820.c
|
||||
gcc -m32 -o $@ unit-linux-loader-e820.c -I. -I../../src -I../../include \
|
||||
-g -DUNIT_TEST -DWOLFBOOT_FSP -DUCODE0_ADDRESS=0 \
|
||||
-DWOLFBOOT_LOAD_BASE=0x100000
|
||||
|
||||
unit-boot-x86-fsp: ../../include/target.h unit-boot-x86_fsp.c
|
||||
gcc -o $@ $^ $(CFLAGS) -DWOLFBOOT_LOAD_BASE=0x100000 -DWOLFBOOT_FSP \
|
||||
-DUCODE0_ADDRESS=0 -ffunction-sections -fdata-sections $(LDFLAGS) \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
/* unit-linux-loader-e820.c
|
||||
*
|
||||
* Regression test for F-4711: e820_add_entry_cb() must not write past the
|
||||
* fixed-size boot_params->e820_table[E820_MAX_ENTRIES_ZEROPAGE] when the FSP
|
||||
* HOB list supplies more resource descriptors than the table can hold.
|
||||
*
|
||||
* Built for x86 32bit (the only target supported by linux_loader.c), without
|
||||
* the check framework, since 32bit libcheck is not generally available.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "x86/hob.h"
|
||||
#include "x86/linux_loader.h"
|
||||
|
||||
#include "../../src/x86/hob.c"
|
||||
#include "../../src/x86/linux_loader.c"
|
||||
|
||||
/* More descriptors than the table can hold, to force the overflow path. */
|
||||
#define N_ENTRIES 200
|
||||
#define CANARY_LEN 2048
|
||||
#define CANARY_BYTE 0xAA
|
||||
|
||||
/* boot_params followed by a canary region: any write past e820_table runs
|
||||
* through the rest of boot_params and into the canary. */
|
||||
static struct {
|
||||
struct boot_params bp;
|
||||
uint8_t canary[CANARY_LEN];
|
||||
} obj;
|
||||
|
||||
static uint8_t hoblist[(N_ENTRIES + 1) *
|
||||
sizeof(struct efi_hob_resource_descriptor)];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
uint8_t *p = hoblist;
|
||||
struct efi_hob_resource_descriptor *rd;
|
||||
struct efi_hob_generic_header *end;
|
||||
|
||||
for (i = 0; i < N_ENTRIES; i++) {
|
||||
rd = (struct efi_hob_resource_descriptor *)p;
|
||||
memset(rd, 0, sizeof(*rd));
|
||||
rd->header.hob_type = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR;
|
||||
rd->header.hob_length = sizeof(struct efi_hob_resource_descriptor);
|
||||
rd->resource_type = EFI_RESOURCE_SYSTEM_MEMORY;
|
||||
rd->physical_start = 0x4141414141414141ULL;
|
||||
rd->resource_length = 0x4242424242424242ULL;
|
||||
p += sizeof(struct efi_hob_resource_descriptor);
|
||||
}
|
||||
end = (struct efi_hob_generic_header *)p;
|
||||
end->hob_type = EFI_HOB_TYPE_END_OF_HOB_LIST;
|
||||
end->hob_length = sizeof(struct efi_hob_generic_header);
|
||||
|
||||
memset(&obj, 0, sizeof(obj));
|
||||
memset(obj.canary, CANARY_BYTE, CANARY_LEN);
|
||||
|
||||
(void)memory_map_from_hoblist(&obj.bp, (struct efi_hob *)hoblist);
|
||||
|
||||
printf("e820_entries=%u\n", obj.bp.e820_entries);
|
||||
|
||||
for (i = 0; i < CANARY_LEN; i++) {
|
||||
if (obj.canary[i] != CANARY_BYTE) {
|
||||
printf("FAIL: e820_table overflow corrupted memory at +%d\n", i);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (obj.bp.e820_entries > E820_MAX_ENTRIES_ZEROPAGE) {
|
||||
printf("FAIL: e820_entries=%u exceeds max %d\n",
|
||||
obj.bp.e820_entries, E820_MAX_ENTRIES_ZEROPAGE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue