From 6c6e3a2b0edf98ed2eff10a38fb74b70ebf60009 Mon Sep 17 00:00:00 2001 From: Alexander Egorenkov Date: Sat, 28 Nov 2020 12:20:41 +0100 Subject: [PATCH] zipl/boot: fix potential heap overflow in stage2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current heap size in stage2 is three pages long [0x6000-0x9000] but get_zeroed_page() assumes it is one page more which might lead to a heap overflow which will corrupt data located at 0x9000 (stage3 parameters). Calculate the heap size of a stage at run-time by using the symbols provided by linker. Furthermore, validate the given address in free_page() to stop illegal memory accesses. Signed-off-by: Alexander Egorenkov Reviewed-by: Philipp Rudo Signed-off-by: Jan Höppner --- zipl/boot/libc.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/zipl/boot/libc.c b/zipl/boot/libc.c index a888c271..c91cc9b3 100644 --- a/zipl/boot/libc.c +++ b/zipl/boot/libc.c @@ -32,9 +32,10 @@ struct ex_table_entry { }; #define MEM_ALLOC_START ((unsigned long) __heap_start) -#define MEM_ALLOC_CNT 4 +#define MEM_ALLOC_END ((unsigned long) __heap_stop) +#define MEM_ALLOC_MAX 4 -static uint8_t mem_page_alloc_vec[MEM_ALLOC_CNT]; +static uint8_t mem_page_alloc_vec[MEM_ALLOC_MAX]; /* * Initialize memory with value @@ -417,10 +418,11 @@ void printf(const char *fmt, ...) */ unsigned long get_zeroed_page(void) { + const int page_count = MIN(MEM_ALLOC_MAX, (int)((MEM_ALLOC_END - MEM_ALLOC_START) / PAGE_SIZE)); unsigned long addr; int i; - for (i = 0; i < MEM_ALLOC_CNT; i++) { + for (i = 0; i < page_count; i++) { if (mem_page_alloc_vec[i] != 0) continue; addr = MEM_ALLOC_START + i * PAGE_SIZE; @@ -436,6 +438,9 @@ unsigned long get_zeroed_page(void) */ void free_page(unsigned long addr) { + if (addr < MEM_ALLOC_START || addr >= MEM_ALLOC_END) + libc_stop(EINTERNAL); + mem_page_alloc_vec[(addr - MEM_ALLOC_START) / PAGE_SIZE] = 0; }