[riscv] Allow for poisoning .bss section before early initialisation

On startup, we may be running from read-only memory, and therefore
cannot zero the .bss section (or write to the .data section) until we
have parsed the system memory map and relocated ourselves to somewhere
suitable in RAM.  The code that runs during this early initialisation
stage must be carefully written to avoid writing to the .data section
and to avoid reading from or writing to the .bss section.

Detecting code that erroneously writes to the .data or .bss sections
is relatively easy since running from read-only memory (e.g. via
QEMU's -pflash option) will immediately reveal the bug.  Detecting
code that erroneously reads from the .bss section is harder, since in
a freshly powered-on machine (or in a virtual machine) there is a high
probability that the contents of the memory will be zero even before
we explicitly zero out the section.

Add the ability to fill the .bss section with an invalid non-zero
value to expose bugs in early initialisation code that erroneously
relies upon variables in .bss before the section has been zeroed.  We
use the value 0xeb55eb55eb55eb55 ("EBSS") since this is immediately
recognisable as a value in a crash dump, and will trigger a page fault
if dereferenced since the address is in a non-canonical form.

Poisoning the .bss can be done only when the image is known to already
reside in writable memory.  It will overwrite the relocation records,
and so can be done only on a system where relocation is known to be
unnecessary (e.g. because paging is supported).  We therefore do not
enable this behaviour by default, but leave it as a configurable
option via the config/fault.h header.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2025-07-30 11:11:00 +01:00
parent e3a6e9230c
commit 5bda1727b4
2 changed files with 54 additions and 0 deletions

View File

@@ -30,6 +30,7 @@
*/
#include <config/serial.h>
#include <config/fault.h>
.section ".note.GNU-stack", "", @progbits
.text
@@ -1268,6 +1269,51 @@ disable_paging_32_xstart:
.section ".bss.disable_paging_32_xcheck", "aw", @nobits
.org . + disable_paging_32_xalign - disable_paging_32_xlen
/*****************************************************************************
*
* Poison .bss section
*
*****************************************************************************
*
* Fill the .bss section with an invalid non-zero value to expose bugs
* in early initialisation code that erroneously relies upon variables
* in .bss before the section has been zeroed.
*
* We use the value 0xeb55eb55eb55eb55 ("EBSS") since this is
* immediately recognisable as a value in a crash dump, and will
* trigger a page fault if dereferenced since the address is in a
* non-canonical form.
*
* Poisoning the .bss will overwrite the relocation records, and so
* can be done only as a debugging step on a system where relocation
* is known to be unnecessary (e.g. because paging is supported).
*
* This function does not require a valid stack pointer, but will
* destroy any existing stack contents if the stack happens to be
* placed within the original .bss section.
*
* Parameters: none
*
* Returns: none
*
*/
.equ poison_bss_value_32, 0xeb55eb55
.equ poison_bss_value_64, 0xeb55eb55eb55eb55
.equ poison_bss_value, _C2 ( poison_bss_value_, __riscv_xlen )
.section ".prefix.poison_bss", "ax", @progbits
poison_bss:
/* Fill .bss section */
la t0, _bss
la t1, _ebss
li t2, poison_bss_value
1: STOREN t2, (t0)
addi t0, t0, ( __riscv_xlen / 8 )
blt t0, t1, 1b
ret
.size poison_bss, . - poison_bss
/*****************************************************************************
*
* Install iPXE to a suitable runtime address
@@ -1328,6 +1374,11 @@ install:
mv s2, ra
la s3, _edata
/* Poison .bss if configured to do so */
#if POISON_BSS
call poison_bss
#endif
/* Attempt to enable paging, if we have temporary page table space */
mv a0, a2
beqz a2, 1f

View File

@@ -32,6 +32,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/* Experience virtual machine migration on every N watchdog checks */
#define VM_MIGRATED_RATE 0
/* Poison .bss section before early execution */
#define POISON_BSS 0
#include <config/local/fault.h>
#endif /* CONFIG_FAULT_H */