Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/utest/configs/components/asan.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# dependencies
CONFIG_RT_CONSOLEBUF_SIZE=1024
CONFIG_RT_USING_CI_ACTION=y

CONFIG_RT_USING_ASAN=y
CONFIG_RT_ASAN_SHADOW_SIZE=65536
CONFIG_RT_ASAN_TRACK_MAX=512
CONFIG_RT_UTEST_ASAN=y
2 changes: 2 additions & 0 deletions .github/workflows/utest_auto_run.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ jobs:
config_file: "components/dfs.cfg"
- platform: { UTEST: "A9", RTT_BSP: "bsp/qemu-vexpress-a9", QEMU_ARCH: "arm", QEMU_MACHINE: "vexpress-a9", SD_FILE: "sd.bin", KERNEL: "standard", "SMP_RUN":"" }
config_file: "components/libc.cfg"
- platform: { UTEST: "A9", RTT_BSP: "bsp/qemu-vexpress-a9", QEMU_ARCH: "arm", QEMU_MACHINE: "vexpress-a9", SD_FILE: "sd.bin", KERNEL: "standard", "SMP_RUN":"" }
config_file: "components/asan.cfg"

env:
TEST_QEMU_ARCH: ${{ matrix.platform.QEMU_ARCH }}
Expand Down
1 change: 1 addition & 0 deletions components/utilities/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -244,5 +244,6 @@ config RT_USING_RESOURCE_ID

rsource "libadt/Kconfig"
rsource "rt-link/Kconfig"
rsource "asan/Kconfig"

endmenu
72 changes: 72 additions & 0 deletions components/utilities/asan/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
menuconfig RT_USING_ASAN
bool "Enable AddressSanitizer (heap overflow & use-after-free check)"
default n
depends on RT_USING_HEAP && !RT_USING_USERHEAP
depends on RT_USING_SMALL_MEM_AS_HEAP || RT_USING_MEMHEAP_AS_HEAP || RT_USING_SLAB_AS_HEAP
depends on !RT_USING_SMP || RT_USING_MUTEX || RT_USING_HEAP_ISR
help
Enable runtime AddressSanitizer (kernel-address) support. It
instruments memory accesses to detect heap buffer overflow and
use-after-free at runtime.

It requires the toolchain to support '-fsanitize=kernel-address'
(GCC 8+, verified on ARM and RISC-V).

The shadow memory is a static array of RT_ASAN_SHADOW_SIZE bytes
and covers the first RT_ASAN_SHADOW_SIZE * 8 bytes of the heap.
Accesses beyond that range are not checked.

Each allocation reserves a size header, alignment padding and at least
8 bytes of right redzone. Realloc grows within its reserved capacity or
allocates and copies the requested user bytes; shrinking keeps capacity.
Aligned allocations also use the requested size for their redzones.
Only the system heap APIs are wrapped; direct allocator/page APIs and
accesses in prebuilt, uninstrumented libraries are not checked.

The component overrides the weak system heap interfaces and owns
the underlying allocator, heap lock and allocation hooks. Do not
combine it with another implementation overriding the same APIs.

SMP requires a mutex or the interrupt-safe heap spinlock to
serialize allocator access across CPUs.

Heap algorithm support:
- small mem (RT_USING_SMALL_MEM_AS_HEAP): full support, detects
both heap-buffer-overflow and use-after-free.
- slab (RT_USING_SLAB_AS_HEAP) and memheap
(RT_USING_MEMHEAP_AS_HEAP): detects heap-buffer-overflow only.
Their allocators reuse freed blocks for internal metadata written
through instrumented rt_memset/rt_memcpy, so poisoning a whole
freed block would raise false positives; use-after-free is
therefore disabled for these two.
- userheap (RT_USING_USERHEAP): not supported (mutually exclusive).

if RT_USING_ASAN
config RT_ASAN_SHADOW_SIZE
int "ASan shadow memory size (bytes)"
default 65536
help
Size of the static shadow memory array. Each byte maps 8
bytes of the heap, so the checked heap range is
RT_ASAN_SHADOW_SIZE * 8 bytes.

config RT_ASAN_TRACK_MAX
int "Max number of tracked active allocations"
default 512
help
Size of the allocation tracking table. Each entry records
one live block (ptr, size, owner thread). Reduce this on
memory-constrained MCUs (e.g. 128 or 64). When the table
is full, further allocations still get redzones and free/realloc
handling, but reports may lack allocation/owner details.

config RT_ASAN_BACKTRACE
bool "Print full backtrace on report"
default y
help
When a violation is reported, also dump the full call stack
of the faulting thread via rt_backtrace(). This requires the
target architecture to implement a backtrace backend (unwind
table or frame pointer chain). Architectures without one
print nothing extra.
endif
23 changes: 23 additions & 0 deletions components/utilities/asan/SConscript
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from building import *
Import('rtconfig')

cwd = GetCurrentDir()
src = Glob('*.c')
CPPPATH = [cwd]
CFLAGS = ''
LINKFLAGS = ''

# DefineGroup adds CFLAGS/CXXFLAGS/LINKFLAGS to the shared build environment.
# The runtime is provided here and does not need libasan.
if rtconfig.PLATFORM == 'gcc':
CFLAGS = ' -fsanitize=kernel-address -fno-omit-frame-pointer'
LINKFLAGS = ' -fsanitize=kernel-address'

# The ASan runtime itself must not be instrumented, otherwise it would
# recurse infinitely. '-fno-sanitize=kernel-address' is appended after the
# global '-fsanitize=kernel-address' and therefore overrides it.
group = DefineGroup('asan', src, depend=['RT_USING_ASAN'], CPPPATH=CPPPATH,
CFLAGS=CFLAGS, CXXFLAGS=CFLAGS, LINKFLAGS=LINKFLAGS,
LOCAL_CFLAGS=' -fno-sanitize=kernel-address')

Return('group')
Loading
Loading