kasan: Implementing global variable out of bounds detection
Extracting global variable information using scripts: kasan_global.py: 1. Extract the global variable information provided by the -- param asan globals=1 option 2. Generate shadow regions for global variable out of bounds detection Makefile: 1. Implement multiple links, embed the shadow area into the program, and call it by the Kasan module Signed-off-by: W-M-R <mike_0528@163.com>
This commit is contained in:
parent
2fd73bd82f
commit
0ede3fc377
@ -180,13 +180,27 @@ $(KBIN): $(OBJS)
|
||||
board$(DELIM)libboard$(LIBEXT):
|
||||
$(Q) $(MAKE) -C board libboard$(LIBEXT) EXTRAFLAGS="$(EXTRAFLAGS)"
|
||||
|
||||
define LINK_ALLSYMS
|
||||
# When multiple linking, these two additional linking objects will be included
|
||||
|
||||
ifeq ($(CONFIG_MM_KASAN_GLOBAL),y)
|
||||
EXTRA_LIBS += kasan_globals$(OBJEXT)
|
||||
endif
|
||||
ifeq ($(CONFIG_ALLSYMS),y)
|
||||
EXTRA_LIBS += allsyms$(OBJEXT)
|
||||
endif
|
||||
|
||||
define LINK_ALLSYMS_KASAN
|
||||
$(if $(CONFIG_ALLSYMS),
|
||||
$(Q) $(TOPDIR)/tools/mkallsyms.py $(NUTTX) allsyms.tmp --orderbyname $(CONFIG_SYMTAB_ORDEREDBYNAME)
|
||||
$(Q) $(call COMPILE, allsyms.tmp, allsyms$(OBJEXT), -x c)
|
||||
$(Q) $(call DELFILE, allsyms.tmp))
|
||||
$(if $(CONFIG_MM_KASAN_GLOBAL),
|
||||
$(Q) $(TOPDIR)/tools/kasan_global.py -e $(NUTTX) -o kasan_globals.tmp
|
||||
$(Q) $(call COMPILE, kasan_globals.tmp, kasan_globals$(OBJEXT) -fno-sanitize=kernel-address, -x c)
|
||||
$(Q) $(call DELFILE, kasan_globals.tmp))
|
||||
$(Q) $(LD) --entry=__start $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \
|
||||
-o $(NUTTX) $(HEAD_OBJ) allsyms$(OBJEXT) $(EXTRA_OBJS) \
|
||||
-o $(NUTTX) $(HEAD_OBJ) $(EXTRA_OBJS) \
|
||||
$(LDSTARTGROUP) $(LDLIBS) $(EXTRA_LIBS) $(LDENDGROUP)
|
||||
$(Q) $(call DELFILE, allsyms.tmp allsyms$(OBJEXT))
|
||||
endef
|
||||
|
||||
$(addsuffix .tmp,$(ARCHSCRIPT)): $(ARCHSCRIPT)
|
||||
@ -194,17 +208,19 @@ $(addsuffix .tmp,$(ARCHSCRIPT)): $(ARCHSCRIPT)
|
||||
|
||||
nuttx$(EXEEXT): $(HEAD_OBJ) board$(DELIM)libboard$(LIBEXT) $(addsuffix .tmp,$(ARCHSCRIPT))
|
||||
$(Q) echo "LD: nuttx"
|
||||
ifneq ($(CONFIG_ALLSYMS),y)
|
||||
ifeq ($(CONFIG_ALLSYMS)$(CONFIG_MM_KASAN_GLOBAL),)
|
||||
$(Q) $(LD) --entry=__start $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \
|
||||
-o $(NUTTX) $(HEAD_OBJ) $(EXTRA_OBJS) \
|
||||
$(LDSTARTGROUP) $(LDLIBS) $(EXTRA_LIBS) $(LDENDGROUP)
|
||||
else
|
||||
$(Q) # Link and generate default table
|
||||
$(Q) $(if $(wildcard $(shell echo $(NUTTX))),,$(call LINK_ALLSYMS,$^))
|
||||
$(Q) # Extract all symbols
|
||||
$(Q) $(call LINK_ALLSYMS, $^)
|
||||
$(Q) # Extract again since the table offset may changed
|
||||
$(Q) $(call LINK_ALLSYMS, $^)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
endif
|
||||
ifeq ($(CONFIG_MM_KASAN_GLOBAL),y)
|
||||
$(Q) $(OBJCOPY) -R .kasan.global $(NUTTX)
|
||||
$(Q) $(OBJCOPY) -R .kasan.unused $(NUTTX)
|
||||
endif
|
||||
ifneq ($(CONFIG_WINDOWS_NATIVE),y)
|
||||
$(Q) $(NM) $(NUTTX) | \
|
||||
|
@ -78,6 +78,10 @@ ifeq ($(CONFIG_MM_KASAN_ALL),y)
|
||||
ARCHOPTIMIZATION += -fsanitize=kernel-address
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MM_KASAN_GLOBAL),y)
|
||||
ARCHOPTIMIZATION += --param asan-globals=1
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MM_KASAN_DISABLE_READS_CHECK),y)
|
||||
ARCHOPTIMIZATION += --param asan-instrument-reads=0
|
||||
endif
|
||||
|
@ -156,13 +156,27 @@ $(KBIN): $(OBJS)
|
||||
board$(DELIM)libboard$(LIBEXT):
|
||||
$(Q) $(MAKE) -C board libboard$(LIBEXT) EXTRAFLAGS="$(EXTRAFLAGS)"
|
||||
|
||||
define LINK_ALLSYMS
|
||||
# When multiple linking, these two additional linking objects will be included
|
||||
|
||||
ifeq ($(CONFIG_MM_KASAN_GLOBAL),y)
|
||||
EXTRA_LIBS += kasan_globals$(OBJEXT)
|
||||
endif
|
||||
ifeq ($(CONFIG_ALLSYMS),y)
|
||||
EXTRA_LIBS += allsyms$(OBJEXT)
|
||||
endif
|
||||
|
||||
define LINK_ALLSYMS_KASAN
|
||||
$(if $(CONFIG_ALLSYMS),
|
||||
$(Q) $(TOPDIR)/tools/mkallsyms.py $(NUTTX) allsyms.tmp --orderbyname $(CONFIG_SYMTAB_ORDEREDBYNAME)
|
||||
$(Q) $(call COMPILE, allsyms.tmp, allsyms$(OBJEXT), -x c)
|
||||
$(Q) $(call DELFILE, allsyms.tmp))
|
||||
$(if $(CONFIG_MM_KASAN_GLOBAL),
|
||||
$(Q) $(TOPDIR)/tools/kasan_global.py -e $(NUTTX) -o kasan_globals.tmp
|
||||
$(Q) $(call COMPILE, kasan_globals.tmp, kasan_globals$(OBJEXT) -fno-sanitize=kernel-address, -x c)
|
||||
$(Q) $(call DELFILE, kasan_globals.tmp))
|
||||
$(Q) $(LD) --entry=__start $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \
|
||||
-o $(NUTTX) $(HEAD_OBJ) allsyms$(OBJEXT) $(EXTRA_OBJS) \
|
||||
-o $(NUTTX) $(HEAD_OBJ) $(EXTRA_OBJS) \
|
||||
$(LDSTARTGROUP) $(LDLIBS) $(EXTRA_LIBS) $(LDENDGROUP)
|
||||
$(Q) $(call DELFILE, allsyms.tmp allsyms$(OBJEXT))
|
||||
endef
|
||||
|
||||
$(addsuffix .tmp,$(ARCHSCRIPT)): $(ARCHSCRIPT)
|
||||
@ -170,17 +184,19 @@ $(addsuffix .tmp,$(ARCHSCRIPT)): $(ARCHSCRIPT)
|
||||
|
||||
nuttx$(EXEEXT): $(HEAD_OBJ) board$(DELIM)libboard$(LIBEXT) $(addsuffix .tmp,$(ARCHSCRIPT))
|
||||
$(Q) echo "LD: nuttx"
|
||||
ifneq ($(CONFIG_ALLSYMS),y)
|
||||
ifeq ($(CONFIG_ALLSYMS)$(CONFIG_MM_KASAN_GLOBAL),)
|
||||
$(Q) $(LD) --entry=__start $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \
|
||||
-o $(NUTTX) $(HEAD_OBJ) $(EXTRA_OBJS) \
|
||||
$(LDSTARTGROUP) $(LDLIBS) $(EXTRA_LIBS) $(LDENDGROUP)
|
||||
else
|
||||
$(Q) # Link and generate default table
|
||||
$(Q) $(if $(wildcard $(shell echo $(NUTTX))),,$(call LINK_ALLSYMS,$^))
|
||||
$(Q) # Extract all symbols
|
||||
$(Q) $(call LINK_ALLSYMS, $^)
|
||||
$(Q) # Extract again since the table offset may changed
|
||||
$(Q) $(call LINK_ALLSYMS, $^)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
endif
|
||||
ifeq ($(CONFIG_MM_KASAN_GLOBAL),y)
|
||||
$(Q) $(OBJCOPY) -R .kasan.global $(NUTTX)
|
||||
$(Q) $(OBJCOPY) -R .kasan.unused $(NUTTX)
|
||||
endif
|
||||
ifneq ($(CONFIG_WINDOWS_NATIVE),y)
|
||||
$(Q) $(NM) $(NUTTX) | \
|
||||
|
@ -84,6 +84,10 @@ ifeq ($(CONFIG_MM_KASAN_ALL),y)
|
||||
ARCHOPTIMIZATION += -fsanitize=kernel-address
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MM_KASAN_GLOBAL),y)
|
||||
ARCHOPTIMIZATION += --param asan-globals=1
|
||||
endif
|
||||
|
||||
# Instrumentation options
|
||||
|
||||
ifeq ($(CONFIG_ARCH_INSTRUMENT_ALL),y)
|
||||
|
@ -162,13 +162,27 @@ $(KBIN): $(OBJS)
|
||||
board/libboard$(LIBEXT):
|
||||
$(Q) $(MAKE) -C board libboard$(LIBEXT) EXTRAFLAGS="$(EXTRAFLAGS)"
|
||||
|
||||
define LINK_ALLSYMS
|
||||
# When multiple linking, these two additional linking objects will be included
|
||||
|
||||
ifeq ($(CONFIG_MM_KASAN_GLOBAL),y)
|
||||
EXTRA_LIBS += kasan_globals$(OBJEXT)
|
||||
endif
|
||||
ifeq ($(CONFIG_ALLSYMS),y)
|
||||
EXTRA_LIBS += allsyms$(OBJEXT)
|
||||
endif
|
||||
|
||||
define LINK_ALLSYMS_KASAN
|
||||
$(if $(CONFIG_ALLSYMS),
|
||||
$(Q) $(TOPDIR)/tools/mkallsyms.py $(NUTTX) allsyms.tmp --orderbyname $(CONFIG_SYMTAB_ORDEREDBYNAME)
|
||||
$(Q) $(call COMPILE, allsyms.tmp, allsyms$(OBJEXT), -x c)
|
||||
$(Q) $(call DELFILE, allsyms.tmp))
|
||||
$(if $(CONFIG_MM_KASAN_GLOBAL),
|
||||
$(Q) $(TOPDIR)/tools/kasan_global.py -e $(NUTTX) -o kasan_globals.tmp
|
||||
$(Q) $(call COMPILE, kasan_globals.tmp, kasan_globals$(OBJEXT) -fno-sanitize=kernel-address, -x c)
|
||||
$(Q) $(call DELFILE, kasan_globals.tmp))
|
||||
$(Q) $(LD) --entry=__start $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \
|
||||
-o $(NUTTX) $(HEAD_OBJ) allsyms$(OBJEXT) $(EXTRA_OBJS) \
|
||||
-o $(NUTTX) $(HEAD_OBJ) $(EXTRA_OBJS) \
|
||||
$(LDSTARTGROUP) $(LDLIBS) $(EXTRA_LIBS) $(LDENDGROUP)
|
||||
$(Q) $(call DELFILE, allsyms.tmp allsyms$(OBJEXT))
|
||||
endef
|
||||
|
||||
$(addsuffix .tmp,$(ARCHSCRIPT)): $(ARCHSCRIPT)
|
||||
@ -176,17 +190,19 @@ $(addsuffix .tmp,$(ARCHSCRIPT)): $(ARCHSCRIPT)
|
||||
|
||||
nuttx$(EXEEXT): $(HEAD_OBJ) board/libboard$(LIBEXT) $(addsuffix .tmp,$(ARCHSCRIPT))
|
||||
$(Q) echo "LD: nuttx"
|
||||
ifneq ($(CONFIG_ALLSYMS),y)
|
||||
ifeq ($(CONFIG_ALLSYMS)$(CONFIG_MM_KASAN_GLOBAL),)
|
||||
$(Q) $(LD) --entry=__start $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \
|
||||
-o $(NUTTX) $(HEAD_OBJ) $(EXTRA_OBJS) \
|
||||
$(LDSTARTGROUP) $(LDLIBS) $(EXTRA_LIBS) $(LDENDGROUP)
|
||||
else
|
||||
$(Q) # Link and generate default table
|
||||
$(Q) $(if $(wildcard $(shell echo $(NUTTX))),,$(call LINK_ALLSYMS,$^))
|
||||
$(Q) # Extract all symbols
|
||||
$(Q) $(call LINK_ALLSYMS, $^)
|
||||
$(Q) # Extract again since the table offset may changed
|
||||
$(Q) $(call LINK_ALLSYMS, $^)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
endif
|
||||
ifeq ($(CONFIG_MM_KASAN_GLOBAL),y)
|
||||
$(Q) $(OBJCOPY) -R .kasan.global $(NUTTX)
|
||||
$(Q) $(OBJCOPY) -R .kasan.unused $(NUTTX)
|
||||
endif
|
||||
ifneq ($(CONFIG_WINDOWS_NATIVE),y)
|
||||
$(Q) $(NM) $(NUTTX) | \
|
||||
|
@ -266,6 +266,10 @@ ifeq ($(CONFIG_MM_KASAN_ALL),y)
|
||||
ARCHOPTIMIZATION += -fsanitize=kernel-address
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MM_KASAN_GLOBAL),y)
|
||||
ARCHOPTIMIZATION += --param asan-globals=1
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MM_KASAN_DISABLE_READS_CHECK),y)
|
||||
ARCHOPTIMIZATION += --param asan-instrument-reads=0
|
||||
endif
|
||||
|
@ -351,17 +351,32 @@ board/libboard$(LIBEXT):
|
||||
nuttx-names.dat: nuttx-names.in
|
||||
$(call PREPROCESS, nuttx-names.in, nuttx-names.dat)
|
||||
|
||||
define LINK_ALLSYMS
|
||||
$(if $(CONFIG_HOST_MACOS), \
|
||||
$(Q) $(TOPDIR)/tools/mkallsyms.sh noconst $(NUTTX) $(CROSSDEV) > allsyms.tmp, \
|
||||
$(Q) $(TOPDIR)/tools/mkallsyms.py $(NUTTX) allsyms.tmp --orderbyname $(CONFIG_SYMTAB_ORDEREDBYNAME))
|
||||
$(Q) $(call COMPILE, allsyms.tmp, allsyms$(OBJEXT), -x c)
|
||||
# When multiple linking, these two additional linking objects will be included
|
||||
|
||||
ifeq ($(CONFIG_MM_KASAN_GLOBAL),y)
|
||||
EXTRALD_OBJ += kasan_globals$(OBJEXT)
|
||||
endif
|
||||
ifeq ($(CONFIG_ALLSYMS),y)
|
||||
EXTRALD_OBJ += allsyms$(OBJEXT)
|
||||
endif
|
||||
|
||||
define LINK_ALLSYMS_KASAN
|
||||
$(if $(CONFIG_ALLSYMS), \
|
||||
$(if $(CONFIG_HOST_MACOS), \
|
||||
$(Q) $(TOPDIR)/tools/mkallsyms.sh noconst $(NUTTX) $(CROSSDEV) > allsyms.tmp, \
|
||||
$(Q) $(TOPDIR)/tools/mkallsyms.py $(NUTTX) allsyms.tmp --orderbyname $(CONFIG_SYMTAB_ORDEREDBYNAME)))
|
||||
$(if $(CONFIG_ALLSYMS), \
|
||||
$(Q) $(call COMPILE, allsyms.tmp, allsyms$(OBJEXT), -x c)
|
||||
$(Q) $(call DELFILE, allsyms.tmp))
|
||||
$(if $(CONFIG_MM_KASAN_GLOBAL),
|
||||
$(Q) $(TOPDIR)/tools/kasan_global.py -e $(NUTTX) -o kasan_globals.tmp
|
||||
$(Q) $(call COMPILE, kasan_globals.tmp, kasan_globals$(OBJEXT) -fno-sanitize=kernel-address, -x c)
|
||||
$(Q) $(call DELFILE, kasan_globals.tmp))
|
||||
$(if $(CONFIG_HAVE_CXX),\
|
||||
$(Q) "$(CXX)" $(CFLAGS) $(LDFLAGS) -o $(NUTTX) \
|
||||
$(HEADOBJ) nuttx.rel $(HOSTOBJS) $(STDLIBS) allsyms$(OBJEXT),\
|
||||
$(HEADOBJ) nuttx.rel $(HOSTOBJS) $(STDLIBS) $(EXTRALD_OBJ),\
|
||||
$(Q) "$(CC)" $(CFLAGS) $(LDFLAGS) -o $(NUTTX) \
|
||||
$(HEADOBJ) nuttx.rel $(HOSTOBJS) $(STDLIBS) allsyms$(OBJEXT))
|
||||
$(Q) $(call DELFILE, allsyms.tmp allsyms$(OBJEXT))
|
||||
$(HEADOBJ) nuttx.rel $(HOSTOBJS) $(STDLIBS) $(EXTRALD_OBJ))
|
||||
endef
|
||||
|
||||
# Note: Use objcopy for Linux because for some reasons visibility=hidden
|
||||
@ -382,17 +397,20 @@ ifneq ($(CONFIG_HOST_MACOS),y)
|
||||
-e 's/__fini_array_start/_sfini/g' -e 's/__fini_array_end/_efini/g' >nuttx.ld
|
||||
$(Q) echo "__init_array_start = .; __init_array_end = .; __fini_array_start = .; __fini_array_end = .;" >>nuttx.ld
|
||||
endif
|
||||
ifneq ($(CONFIG_ALLSYMS),y)
|
||||
ifeq ($(CONFIG_MM_KASAN_GLOBAL),y)
|
||||
$(Q) sed -i 's/\s*\.interp\s*:\s*{\s*\*(\.interp)\s*}/ \
|
||||
.kasan.global : {KEEP(*(.data..LASAN0)) KEEP (*(.data.rel.local..LASAN0)) }\n \
|
||||
.interp : {*(.interp)}/g' nuttx.ld
|
||||
endif
|
||||
ifeq ($(CONFIG_ALLSYMS)$(CONFIG_MM_KASAN_GLOBAL),)
|
||||
$(if $(CONFIG_HAVE_CXX),\
|
||||
$(Q) "$(CXX)" $(CFLAGS) $(LDFLAGS) -o $(TOPDIR)/$@ $(HEADOBJ) nuttx.rel $(HOSTOBJS) $(STDLIBS),\
|
||||
$(Q) "$(CC)" $(CFLAGS) $(LDFLAGS) -o $(TOPDIR)/$@ $(HEADOBJ) nuttx.rel $(HOSTOBJS) $(STDLIBS))
|
||||
else
|
||||
$(Q) # Link and generate default table
|
||||
$(Q) $(if $(wildcard $(shell echo $(NUTTX))),,$(call LINK_ALLSYMS, $@))
|
||||
$(Q) # Extract all symbols
|
||||
$(Q) $(call LINK_ALLSYMS, $^)
|
||||
$(Q) # Extract again since the table offset may changed
|
||||
$(Q) $(call LINK_ALLSYMS, $^)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
$(Q) $(call LINK_ALLSYMS_KASAN)
|
||||
endif
|
||||
$(Q) $(NM) $(TOPDIR)/$@ | \
|
||||
grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \
|
||||
|
@ -26,6 +26,20 @@ PHDRS
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x40101000;
|
||||
|
||||
/* where the global variable out-of-bounds detection information located */
|
||||
#ifdef CONFIG_MM_KASAN_GLOBAL
|
||||
.kasan.unused :
|
||||
{
|
||||
*(.data..LASANLOC*)
|
||||
} > ROM
|
||||
.kasan.global :
|
||||
{
|
||||
KEEP (*(.data..LASAN0))
|
||||
KEEP (*(.data.rel.local..LASAN0))
|
||||
} > ROM
|
||||
#endif
|
||||
|
||||
.text : {
|
||||
_stext = .; /* Text section */
|
||||
*(.vectors)
|
||||
|
@ -18,6 +18,8 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
OUTPUT_ARCH(aarch64)
|
||||
|
||||
ENTRY(__start)
|
||||
@ -30,6 +32,20 @@ PHDRS
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x40280000; /* uboot load address */
|
||||
|
||||
/* where the global variable out-of-bounds detection information located */
|
||||
#ifdef CONFIG_MM_KASAN_GLOBAL
|
||||
.kasan.unused :
|
||||
{
|
||||
*(.data..LASANLOC*)
|
||||
}
|
||||
.kasan.global :
|
||||
{
|
||||
KEEP (*(.data..LASAN0))
|
||||
KEEP (*(.data.rel.local..LASAN0))
|
||||
}
|
||||
#endif
|
||||
|
||||
_start = .;
|
||||
.text : {
|
||||
_stext = .; /* Text section */
|
||||
|
@ -44,6 +44,19 @@ SECTIONS
|
||||
{
|
||||
. = 0x80000000;
|
||||
|
||||
/* where the global variable out-of-bounds detection information located */
|
||||
#ifdef CONFIG_MM_KASAN_GLOBAL
|
||||
.kasan.unused :
|
||||
{
|
||||
*(.data..LASANLOC*)
|
||||
}
|
||||
.kasan.global :
|
||||
{
|
||||
KEEP (*(.data..LASAN0))
|
||||
KEEP (*(.data.rel.local..LASAN0))
|
||||
}
|
||||
#endif
|
||||
|
||||
.text :
|
||||
{
|
||||
_stext = . ;
|
||||
|
@ -44,6 +44,19 @@ SECTIONS
|
||||
{
|
||||
. = 0x80000000;
|
||||
|
||||
/* where the global variable out-of-bounds detection information located */
|
||||
#ifdef CONFIG_MM_KASAN_GLOBAL
|
||||
.kasan.unused :
|
||||
{
|
||||
*(.data..LASANLOC*)
|
||||
}
|
||||
.kasan.global :
|
||||
{
|
||||
KEEP (*(.data..LASAN0))
|
||||
KEEP (*(.data.rel.local..LASAN0))
|
||||
}
|
||||
#endif
|
||||
|
||||
.text :
|
||||
{
|
||||
_stext = . ;
|
||||
|
@ -22,6 +22,19 @@ SECTIONS
|
||||
{
|
||||
. = 0x80000000;
|
||||
|
||||
/* where the global variable out-of-bounds detection information located */
|
||||
#ifdef CONFIG_MM_KASAN_GLOBAL
|
||||
.kasan.unused :
|
||||
{
|
||||
*(.data..LASANLOC*)
|
||||
}
|
||||
.kasan.global :
|
||||
{
|
||||
KEEP (*(.data..LASAN0))
|
||||
KEEP (*(.data.rel.local..LASAN0))
|
||||
}
|
||||
#endif
|
||||
|
||||
.text :
|
||||
{
|
||||
_stext = . ;
|
||||
|
@ -83,6 +83,10 @@ else ifeq ($(CONFIG_MM_KASAN_ALL),y)
|
||||
ARCHOPTIMIZATION += -fsanitize=kernel-address
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MM_KASAN_GLOBAL),y)
|
||||
ARCHOPTIMIZATION += --param asan-globals=1
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SIM_UBSAN),y)
|
||||
ARCHOPTIMIZATION += -fsanitize=undefined
|
||||
else
|
||||
|
15
mm/Kconfig
15
mm/Kconfig
@ -281,6 +281,21 @@ config MM_KASAN_DISABLE_WRITES_CHECK
|
||||
---help---
|
||||
This option disable kasan writes check.
|
||||
|
||||
config MM_KASAN_GLOBAL
|
||||
bool "Enable global data check"
|
||||
depends on MM_KASAN
|
||||
default n
|
||||
---help---
|
||||
This option enables KASan global data check.
|
||||
It's used to extract segments in the linker script.
|
||||
Two new segments need to be created, one being
|
||||
".kasan.unused: { *(.data..LASANLOC*) }",
|
||||
used to eliminate excess data generated.
|
||||
One is ".kasan.global:{
|
||||
KEEP ( *(. data.. LASAN0))
|
||||
KEEP ( *(. data. rel. local.. LASAN0))
|
||||
}", used to extract data generated by the compiler
|
||||
|
||||
config MM_UBSAN
|
||||
bool "Undefined Behavior Sanitizer"
|
||||
default n
|
||||
|
@ -50,6 +50,16 @@
|
||||
#define KASAN_REGION_SIZE(size) \
|
||||
(sizeof(struct kasan_region_s) + KASAN_SHADOW_SIZE(size))
|
||||
|
||||
#ifdef CONFIG_MM_KASAN_GLOBAL
|
||||
|
||||
# define KASAN_GLOBAL_SHADOW_SCALE (32)
|
||||
|
||||
# define KASAN_GLOBAL_NEXT_REGION(region) \
|
||||
(FAR struct kasan_region_s *) \
|
||||
((FAR char *)region->shadow + (size_t)region->next)
|
||||
|
||||
#endif
|
||||
|
||||
#define KASAN_INIT_VALUE 0xDEADCAFE
|
||||
|
||||
/****************************************************************************
|
||||
@ -59,9 +69,9 @@
|
||||
struct kasan_region_s
|
||||
{
|
||||
FAR struct kasan_region_s *next;
|
||||
uintptr_t begin;
|
||||
uintptr_t end;
|
||||
uintptr_t shadow[1];
|
||||
uintptr_t begin;
|
||||
uintptr_t end;
|
||||
uintptr_t shadow[1];
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
@ -72,6 +82,14 @@ static spinlock_t g_lock;
|
||||
static FAR struct kasan_region_s *g_region;
|
||||
static uint32_t g_region_init;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MM_KASAN_GLOBAL
|
||||
extern const unsigned char g_globals_region[];
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
@ -99,6 +117,22 @@ static FAR uintptr_t *kasan_mem_to_shadow(FAR const void *ptr, size_t size,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MM_KASAN_GLOBAL
|
||||
for (region = (FAR struct kasan_region_s *)g_globals_region;
|
||||
region->next;
|
||||
region = KASAN_GLOBAL_NEXT_REGION(region))
|
||||
{
|
||||
if (addr >= region->begin && addr < region->end)
|
||||
{
|
||||
DEBUGASSERT(addr + size <= region->end);
|
||||
addr -= region->begin;
|
||||
addr /= KASAN_GLOBAL_SHADOW_SCALE;
|
||||
*bit = addr % KASAN_BITS_PER_WORD;
|
||||
return ®ion->shadow[addr / KASAN_BITS_PER_WORD];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -314,3 +348,15 @@ DEFINE_ASAN_LOAD_STORE(2)
|
||||
DEFINE_ASAN_LOAD_STORE(4)
|
||||
DEFINE_ASAN_LOAD_STORE(8)
|
||||
DEFINE_ASAN_LOAD_STORE(16)
|
||||
|
||||
#ifdef CONFIG_MM_KASAN_GLOBAL
|
||||
void __asan_register_globals(void *ptr, ssize_t size)
|
||||
{
|
||||
/* Shut up compiler complaints */
|
||||
}
|
||||
|
||||
void __asan_unregister_globals(void *ptr, ssize_t size)
|
||||
{
|
||||
/* Shut up compiler complaints */
|
||||
}
|
||||
#endif
|
||||
|
306
tools/kasan_global.py
Executable file
306
tools/kasan_global.py
Executable file
@ -0,0 +1,306 @@
|
||||
#!/usr/bin/env python3
|
||||
############################################################################
|
||||
# tools/kasan_global.py
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership. The
|
||||
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance with the
|
||||
# License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
from construct import Int32ul, Int64ul, Struct
|
||||
from elftools.elf.elffile import ELFFile
|
||||
|
||||
debug = False
|
||||
|
||||
# N-byte aligned shadow area 1 bit
|
||||
KASAN_GLOBAL_ALIGN = 32
|
||||
|
||||
# The maximum gap that two data segments can tolerate
|
||||
KASAN_MAX_DATA_GAP = 1 << 16
|
||||
|
||||
# The section where the global variable descriptor
|
||||
# generated by the compiler is located
|
||||
KASAN_SECTION = ".kasan.global"
|
||||
|
||||
# The structure of parsing strings required for 32-bit and 64 bit
|
||||
KASAN_GLOBAL_STRUCT_32 = Struct(
|
||||
"beg" / Int32ul,
|
||||
"size" / Int32ul,
|
||||
"size_with_redzone" / Int32ul,
|
||||
"name" / Int32ul,
|
||||
"module_name" / Int32ul,
|
||||
"has_dynamic_init" / Int32ul,
|
||||
"location" / Int32ul,
|
||||
"odr_indicator" / Int32ul,
|
||||
)
|
||||
|
||||
KASAN_GLOBAL_STRUCT_64 = Struct(
|
||||
"beg" / Int64ul,
|
||||
"size" / Int64ul,
|
||||
"size_with_redzone" / Int64ul,
|
||||
"name" / Int64ul,
|
||||
"module_name" / Int64ul,
|
||||
"has_dynamic_init" / Int64ul,
|
||||
"location" / Int64ul,
|
||||
"odr_indicator" / Int64ul,
|
||||
)
|
||||
|
||||
|
||||
# Global configuration information
|
||||
class Config:
|
||||
def __init__(self, outpath, elf, ldscript):
|
||||
self.outpath = outpath
|
||||
self.elf = elf
|
||||
self.ldscript = ldscript
|
||||
|
||||
if self.elf is None or os.path.exists(self.elf) is False:
|
||||
self.elf = None
|
||||
return
|
||||
|
||||
with open(self.elf, "rb") as file:
|
||||
elf_file = ELFFile(file)
|
||||
elf_header = elf_file.header
|
||||
|
||||
# Obtain bit width
|
||||
bitness = elf_header["e_ident"]["EI_CLASS"]
|
||||
if bitness == "ELFCLASS32":
|
||||
self.bitwides = 32
|
||||
elif bitness == "ELFCLASS64":
|
||||
self.bitwides = 64
|
||||
|
||||
# Big and little end
|
||||
endianness = elf_header["e_ident"]["EI_DATA"]
|
||||
if endianness == "ELFDATA2LSB":
|
||||
self.endian = "little"
|
||||
elif endianness == "ELFDATA2MSB":
|
||||
self.endian = "big"
|
||||
|
||||
|
||||
class KASanRegion:
|
||||
def __init__(self, start, end) -> None:
|
||||
self.start = start
|
||||
self.end = end
|
||||
self.size = int((end - start) // KASAN_GLOBAL_ALIGN // 8) + 1
|
||||
self.shadow = bytearray(b"\x00" * self.size)
|
||||
|
||||
def mark_bit(self, index, nbits):
|
||||
self.shadow[index] |= 1 << nbits
|
||||
|
||||
def poison(self, dict):
|
||||
dict_size = dict["size"]
|
||||
if dict_size % 32:
|
||||
dict_size = int((dict_size + 31) // 32) * 32
|
||||
|
||||
distance = (dict["beg"] + dict_size - self.start) // KASAN_GLOBAL_ALIGN
|
||||
index = int(distance // 8)
|
||||
nbits = distance % 8
|
||||
if debug:
|
||||
print(
|
||||
"regin: %08x addr: %08x size: %d bits: %d || poison index: %d nbits: %d"
|
||||
% (
|
||||
self.start,
|
||||
dict["beg"],
|
||||
dict["size"],
|
||||
int(dict["size_with_redzone"] // KASAN_GLOBAL_ALIGN),
|
||||
index,
|
||||
nbits,
|
||||
)
|
||||
)
|
||||
|
||||
# Using 32bytes: with 1bit alignment,
|
||||
# only one bit of inaccessible area exists for each pair of global variables.
|
||||
self.mark_bit(index, nbits)
|
||||
|
||||
|
||||
class KASanInfo:
|
||||
def __init__(self) -> None:
|
||||
# Record the starting position of the merged data block
|
||||
self.data_sections = []
|
||||
# Record the kasan region corresponding to each data block
|
||||
self.regions: list[KASanRegion] = []
|
||||
|
||||
def merge_ranges(self, dict):
|
||||
if len(self.data_sections) == 0:
|
||||
self.data_sections.append(
|
||||
[dict["beg"], dict["beg"] + dict["size_with_redzone"]]
|
||||
)
|
||||
return
|
||||
start = dict["beg"]
|
||||
end = dict["beg"] + dict["size_with_redzone"]
|
||||
if start - self.data_sections[-1][1] <= KASAN_MAX_DATA_GAP:
|
||||
self.data_sections[-1][1] = end
|
||||
else:
|
||||
self.data_sections.append([start, end])
|
||||
|
||||
def create_region(self):
|
||||
for i in self.data_sections:
|
||||
start = i[0]
|
||||
end = i[1]
|
||||
if debug:
|
||||
print("KAsan Shadow Block: %08x ---- %08x" % (start, end))
|
||||
self.regions.append(KASanRegion(start, end))
|
||||
|
||||
def mark_shadow(self, dict):
|
||||
for i in self.regions:
|
||||
start = i.start
|
||||
end = i.end
|
||||
if start <= dict["beg"] and dict["beg"] <= end:
|
||||
i.poison(dict)
|
||||
break
|
||||
|
||||
|
||||
# Global variable descriptor
|
||||
def get_global_dict(GLOBAL_STRUCT: Struct, bytes: bytes):
|
||||
dict = GLOBAL_STRUCT.parse(bytes)
|
||||
return {
|
||||
"beg": dict.beg,
|
||||
"size": dict.size,
|
||||
"size_with_redzone": dict.size_with_redzone,
|
||||
}
|
||||
|
||||
|
||||
def get_elf_section(elf, section) -> bytes:
|
||||
with open(elf, "rb") as file:
|
||||
elf = ELFFile(file)
|
||||
for i in elf.iter_sections():
|
||||
if i.name == section:
|
||||
return i.data()
|
||||
return None
|
||||
|
||||
|
||||
def long_to_bytestring(bitwides, endian, value: int) -> str:
|
||||
res = ""
|
||||
byte_array = value.to_bytes(length=int(bitwides / 8), byteorder=endian)
|
||||
for i in byte_array:
|
||||
res += "0x%02x, " % (i)
|
||||
return res
|
||||
|
||||
|
||||
def create_kasan_file(config: Config, region_list=[]):
|
||||
region: KASanRegion = None
|
||||
with open(config.outpath, "w") as file:
|
||||
file.write("const unsigned char\ng_globals_region[] = {\n")
|
||||
for i in range(len(region_list)):
|
||||
region = region_list[i]
|
||||
|
||||
# Fill the array of regions
|
||||
# The filling order is as follows, from mm/kasan/generic.c
|
||||
# The data set to 0 is assigned by the program body
|
||||
# 1. FAR struct kasan_region_s *next;
|
||||
# This type will be used to record the size of the shadow area
|
||||
# to facilitate the program to traverse the array.
|
||||
# 2. uintptr_t begin;
|
||||
# 3. uintptr_t end;
|
||||
# 4. uintptr_t shadow[1];
|
||||
|
||||
file.write(
|
||||
"%s\n"
|
||||
% (long_to_bytestring(config.bitwides, config.endian, region.size))
|
||||
)
|
||||
file.write(
|
||||
"%s\n"
|
||||
% (long_to_bytestring(config.bitwides, config.endian, region.start))
|
||||
)
|
||||
file.write(
|
||||
"%s\n"
|
||||
% (long_to_bytestring(config.bitwides, config.endian, region.end))
|
||||
)
|
||||
|
||||
for j in range(len(region.shadow)):
|
||||
if j % 8 == 0:
|
||||
file.write("\n")
|
||||
file.write("0x%02x, " % (region.shadow[j]))
|
||||
|
||||
file.write("\n")
|
||||
file.write("0x00, 0x00, 0x00, 0x00,0x00, 0x00,0x00, 0x00\n")
|
||||
file.write("\n};")
|
||||
|
||||
|
||||
# Error extraction section processing to enable the program to compile successfully
|
||||
def handle_error(config: Config, string=None):
|
||||
if string:
|
||||
print(string)
|
||||
create_kasan_file(config)
|
||||
exit(0)
|
||||
|
||||
|
||||
def parse_args() -> Config:
|
||||
global debug
|
||||
parser = argparse.ArgumentParser(description="Build kasan global variable region")
|
||||
parser.add_argument("-o", "--outpath", help="outpath")
|
||||
parser.add_argument("-d", "--ldscript", help="ld script path(Only support sim)")
|
||||
parser.add_argument("-e", "--elffile", help="elffile")
|
||||
parser.add_argument(
|
||||
"--debug",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="if enabled, it will show more logs.",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
debug = args.debug
|
||||
return Config(args.outpath, args.elffile, args.ldscript)
|
||||
|
||||
|
||||
def main():
|
||||
config = parse_args()
|
||||
if config.elf is None:
|
||||
handle_error(config)
|
||||
|
||||
# Identify the segment information that needs to be extracted
|
||||
section = get_elf_section(config.elf, KASAN_SECTION)
|
||||
if section is None:
|
||||
handle_error(
|
||||
config,
|
||||
"Please update the link script, section ['%s'] cannot be found"
|
||||
% (KASAN_SECTION),
|
||||
)
|
||||
|
||||
# List of global variable descriptors
|
||||
dict_list = []
|
||||
|
||||
# Extract all global variable descriptors within the
|
||||
if config.bitwides == 32:
|
||||
global_struct = KASAN_GLOBAL_STRUCT_32
|
||||
elif config.bitwides == 64:
|
||||
global_struct = KASAN_GLOBAL_STRUCT_64
|
||||
|
||||
step = global_struct.sizeof()
|
||||
for i in range(0, len(section), step):
|
||||
dict = get_global_dict(global_struct, section[i : i + step])
|
||||
dict_list.append(dict)
|
||||
|
||||
dict_list = sorted(dict_list, key=lambda item: item["beg"])
|
||||
|
||||
# Merge all global variables to obtain several segments of the distribution range
|
||||
kasan = KASanInfo()
|
||||
for i in dict_list:
|
||||
kasan.merge_ranges(i)
|
||||
|
||||
# Create empty shadow zone
|
||||
kasan.create_region()
|
||||
|
||||
# Mark on the shadow area
|
||||
for i in dict_list:
|
||||
kasan.mark_shadow(i)
|
||||
|
||||
create_kasan_file(config, kasan.regions)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
x
Reference in New Issue
Block a user