lib: Add ASan support to romstage on x86 arch
This patch adds ASan support to romstage on x86 architecture. A Kconfig option is added to enable ASan in romstage. Compiler flags are updated. A memory space representing the shadow region is reserved in linker section. And a function call to asan_init() is added to initialize shadow region when romstage loads. Change-Id: I67ebfb5e8d602e865b1f5c874860861ae4e54381 Signed-off-by: Harshit Sharma <harshitsharmajs@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/43604 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
This commit is contained in:
parent
9c88fb8df0
commit
a6ebe08333
6 changed files with 66 additions and 10 deletions
|
@ -288,6 +288,13 @@ if ASAN_IN_RAMSTAGE
|
||||||
comment "asan_shadow_offset_callback patch is applied to GCC."
|
comment "asan_shadow_offset_callback patch is applied to GCC."
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
config ASAN_IN_ROMSTAGE
|
||||||
|
bool
|
||||||
|
depends on ASAN_IN_RAMSTAGE
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Enable address sanitizer in romstage for platform.
|
||||||
|
|
||||||
choice
|
choice
|
||||||
prompt "Stage Cache for ACPI S3 resume"
|
prompt "Stage Cache for ACPI S3 resume"
|
||||||
default NO_STAGE_CACHE if !HAVE_ACPI_RESUME
|
default NO_STAGE_CACHE if !HAVE_ACPI_RESUME
|
||||||
|
|
|
@ -49,6 +49,10 @@ debug_spinloop:
|
||||||
#if CONFIG(IDT_IN_EVERY_STAGE)
|
#if CONFIG(IDT_IN_EVERY_STAGE)
|
||||||
call exception_init
|
call exception_init
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG(ASAN_IN_ROMSTAGE)
|
||||||
|
call asan_init
|
||||||
|
#endif
|
||||||
call car_stage_entry
|
call car_stage_entry
|
||||||
|
|
||||||
/* Expect to never return. */
|
/* Expect to never return. */
|
||||||
|
|
|
@ -72,8 +72,12 @@
|
||||||
*(.sbss.*)
|
*(.sbss.*)
|
||||||
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
. = ALIGN(ARCH_POINTER_ALIGN_SIZE);
|
||||||
_ebss = .;
|
_ebss = .;
|
||||||
_car_unallocated_start = .;
|
|
||||||
|
|
||||||
|
#if ENV_ROMSTAGE && CONFIG(ASAN_IN_ROMSTAGE)
|
||||||
|
_shadow_size = (_ebss - _car_region_start) >> 3;
|
||||||
|
REGION(asan_shadow, ., _shadow_size, ARCH_POINTER_ALIGN_SIZE)
|
||||||
|
#endif
|
||||||
|
_car_unallocated_start = .;
|
||||||
_car_region_end = . + CONFIG_DCACHE_RAM_SIZE - (. - _car_region_start);
|
_car_region_end = . + CONFIG_DCACHE_RAM_SIZE - (. - _car_region_start);
|
||||||
}
|
}
|
||||||
. = _car_region_end;
|
. = _car_region_end;
|
||||||
|
|
|
@ -24,7 +24,12 @@ DECLARE_REGION(cbfs_cache)
|
||||||
DECLARE_REGION(fmap_cache)
|
DECLARE_REGION(fmap_cache)
|
||||||
DECLARE_REGION(tpm_tcpa_log)
|
DECLARE_REGION(tpm_tcpa_log)
|
||||||
|
|
||||||
#if CONFIG(ASAN_IN_RAMSTAGE)
|
#if ENV_ROMSTAGE && CONFIG(ASAN_IN_ROMSTAGE)
|
||||||
|
DECLARE_REGION(bss)
|
||||||
|
DECLARE_REGION(asan_shadow)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ENV_RAMSTAGE && CONFIG(ASAN_IN_RAMSTAGE)
|
||||||
DECLARE_REGION(data)
|
DECLARE_REGION(data)
|
||||||
DECLARE_REGION(heap)
|
DECLARE_REGION(heap)
|
||||||
DECLARE_REGION(asan_shadow)
|
DECLARE_REGION(asan_shadow)
|
||||||
|
|
|
@ -7,16 +7,24 @@ ramstage-y += ubsan.c
|
||||||
CFLAGS_ramstage += -fsanitize=undefined
|
CFLAGS_ramstage += -fsanitize=undefined
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_ASAN_IN_RAMSTAGE),y)
|
|
||||||
ramstage-y += asan.c
|
|
||||||
# Ensure that asan_shadow_offset_callback patch is applied to GCC before ASan is used.
|
# Ensure that asan_shadow_offset_callback patch is applied to GCC before ASan is used.
|
||||||
CFLAGS_asan += -fsanitize=kernel-address --param asan-use-shadow-offset-callback=1 \
|
CFLAGS_asan += -fsanitize=kernel-address --param asan-use-shadow-offset-callback=1 \
|
||||||
--param asan-stack=1 --param asan-globals=1 \
|
--param asan-stack=1 -fsanitize-address-use-after-scope \
|
||||||
--param asan-instrumentation-with-call-threshold=0 \
|
--param asan-instrumentation-with-call-threshold=0 \
|
||||||
-fsanitize-address-use-after-scope \
|
|
||||||
--param use-after-scope-direct-emission-threshold=0
|
--param use-after-scope-direct-emission-threshold=0
|
||||||
CFLAGS_ramstage += $(CFLAGS_asan)
|
|
||||||
|
ifeq ($(CONFIG_ASAN_IN_ROMSTAGE),y)
|
||||||
|
romstage-y += asan.c
|
||||||
|
CFLAGS_asan += --param asan-globals=0
|
||||||
|
CFLAGS_romstage += $(CFLAGS_asan)
|
||||||
# Allow memory access without __asan_load and __asan_store checks.
|
# Allow memory access without __asan_load and __asan_store checks.
|
||||||
|
$(obj)/romstage/lib/asan.o: CFLAGS_asan =
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_ASAN_IN_RAMSTAGE),y)
|
||||||
|
ramstage-y += asan.c
|
||||||
|
CFLAGS_asan += --param asan-globals=1
|
||||||
|
CFLAGS_ramstage += $(CFLAGS_asan)
|
||||||
$(obj)/ramstage/lib/asan.o: CFLAGS_asan =
|
$(obj)/ramstage/lib/asan.o: CFLAGS_asan =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -10,18 +10,29 @@
|
||||||
|
|
||||||
#include <symbols.h>
|
#include <symbols.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <arch/symbols.h>
|
||||||
#include <asan.h>
|
#include <asan.h>
|
||||||
|
|
||||||
static inline void *asan_mem_to_shadow(const void *addr)
|
static inline void *asan_mem_to_shadow(const void *addr)
|
||||||
{
|
{
|
||||||
|
#if ENV_ROMSTAGE
|
||||||
|
return (void *)((uintptr_t)&_asan_shadow + (((uintptr_t)addr -
|
||||||
|
(uintptr_t)&_car_region_start) >> ASAN_SHADOW_SCALE_SHIFT));
|
||||||
|
#elif ENV_RAMSTAGE
|
||||||
return (void *)((uintptr_t)&_asan_shadow + (((uintptr_t)addr -
|
return (void *)((uintptr_t)&_asan_shadow + (((uintptr_t)addr -
|
||||||
(uintptr_t)&_data) >> ASAN_SHADOW_SCALE_SHIFT));
|
(uintptr_t)&_data) >> ASAN_SHADOW_SCALE_SHIFT));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const void *asan_shadow_to_mem(const void *shadow_addr)
|
static inline const void *asan_shadow_to_mem(const void *shadow_addr)
|
||||||
{
|
{
|
||||||
|
#if ENV_ROMSTAGE
|
||||||
|
return (void *)((uintptr_t)&_car_region_start + (((uintptr_t)shadow_addr -
|
||||||
|
(uintptr_t)&_asan_shadow) << ASAN_SHADOW_SCALE_SHIFT));
|
||||||
|
#elif ENV_RAMSTAGE
|
||||||
return (void *)((uintptr_t)&_data + (((uintptr_t)shadow_addr -
|
return (void *)((uintptr_t)&_data + (((uintptr_t)shadow_addr -
|
||||||
(uintptr_t)&_asan_shadow) << ASAN_SHADOW_SCALE_SHIFT));
|
(uintptr_t)&_asan_shadow) << ASAN_SHADOW_SCALE_SHIFT));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void asan_poison_shadow(const void *address, size_t size, u8 value)
|
static void asan_poison_shadow(const void *address, size_t size, u8 value)
|
||||||
|
@ -225,10 +236,15 @@ static __always_inline void check_memory_region_inline(unsigned long addr,
|
||||||
size_t size, bool write,
|
size_t size, bool write,
|
||||||
unsigned long ret_ip)
|
unsigned long ret_ip)
|
||||||
{
|
{
|
||||||
if (((uintptr_t)addr < (uintptr_t)&_data) ||
|
#if ENV_ROMSTAGE
|
||||||
((uintptr_t)addr > (uintptr_t)&_eheap))
|
if (((uintptr_t)addr < (uintptr_t)&_car_region_start) ||
|
||||||
|
((uintptr_t)addr > (uintptr_t)&_ebss))
|
||||||
return;
|
return;
|
||||||
|
#elif ENV_RAMSTAGE
|
||||||
|
if (((uintptr_t)addr < (uintptr_t)&_data) ||
|
||||||
|
((uintptr_t)addr > (uintptr_t)&_eheap))
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
if (unlikely(size == 0))
|
if (unlikely(size == 0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -252,8 +268,13 @@ static void check_memory_region(unsigned long addr, size_t size, bool write,
|
||||||
|
|
||||||
uintptr_t __asan_shadow_offset(uintptr_t addr)
|
uintptr_t __asan_shadow_offset(uintptr_t addr)
|
||||||
{
|
{
|
||||||
|
#if ENV_ROMSTAGE
|
||||||
|
return (uintptr_t)&_asan_shadow - (((uintptr_t)&_car_region_start) >>
|
||||||
|
ASAN_SHADOW_SCALE_SHIFT);
|
||||||
|
#elif ENV_RAMSTAGE
|
||||||
return (uintptr_t)&_asan_shadow - (((uintptr_t)&_data) >>
|
return (uintptr_t)&_asan_shadow - (((uintptr_t)&_data) >>
|
||||||
ASAN_SHADOW_SCALE_SHIFT);
|
ASAN_SHADOW_SCALE_SHIFT);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void register_global(struct asan_global *global)
|
static void register_global(struct asan_global *global)
|
||||||
|
@ -285,6 +306,7 @@ void __asan_unregister_globals(struct asan_global *globals, size_t size)
|
||||||
* to it so we could poison variable's redzone.
|
* to it so we could poison variable's redzone.
|
||||||
* This function calls those constructors.
|
* This function calls those constructors.
|
||||||
*/
|
*/
|
||||||
|
#if ENV_RAMSTAGE
|
||||||
static void asan_ctors(void)
|
static void asan_ctors(void)
|
||||||
{
|
{
|
||||||
extern long __CTOR_LIST__;
|
extern long __CTOR_LIST__;
|
||||||
|
@ -296,12 +318,18 @@ static void asan_ctors(void)
|
||||||
for (; *ctor != (func_ptr) 0; ctor++)
|
for (; *ctor != (func_ptr) 0; ctor++)
|
||||||
(*ctor)();
|
(*ctor)();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void asan_init(void)
|
void asan_init(void)
|
||||||
{
|
{
|
||||||
|
#if ENV_ROMSTAGE
|
||||||
|
size_t size = (size_t)&_ebss - (size_t)&_car_region_start;
|
||||||
|
asan_unpoison_shadow((void *)&_car_region_start, size);
|
||||||
|
#elif ENV_RAMSTAGE
|
||||||
size_t size = (size_t)&_eheap - (size_t)&_data;
|
size_t size = (size_t)&_eheap - (size_t)&_data;
|
||||||
asan_unpoison_shadow((void *)&_data, size);
|
asan_unpoison_shadow((void *)&_data, size);
|
||||||
asan_ctors();
|
asan_ctors();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void __asan_poison_stack_memory(const void *addr, size_t size)
|
void __asan_poison_stack_memory(const void *addr, size_t size)
|
||||||
|
|
Loading…
Reference in a new issue