arch/posix: Add MemorySanitizer support

Wire this up the same way ASAN works.  Right now it's support only by
recent clang versions (not gcc), and only in 64 bit mode.  But it's
capable of detecting uninitialized data reads, which ASAN is not.

This support is wired into the sys_heap (and thus k_heap/k_malloc)
layers, allowing detection of heap misuse like use-after-free.  Note
that there is one false negative lurking: due to complexity, in the
case where a sys_heap_realloc() call is able to shrink memory in
place, the now-unused suffix is not marked uninitialized immediately,
making it impossible to detect use-after-free of those particular
bytes.  But the system will recover cleanly the next time the memory
gets allocated.

Also no attempt was made to integrate this handling into the newlib or
picolibc allocators, though that should hopefully be possible via
similar means.

Signed-off-by: Andy Ross <andyross@google.com>
This commit is contained in:
Andy Ross 2022-08-16 11:42:53 -07:00 committed by Alberto Escolar
commit 02b23f3733
3 changed files with 24 additions and 0 deletions

View file

@ -53,6 +53,10 @@ if(CONFIG_ASAN)
list(APPEND LLVM_SANITIZERS "address")
endif()
if(CONFIG_MSAN)
list(APPEND LLVM_SANITIZERS "memory")
endif()
if(CONFIG_UBSAN)
list(APPEND LLVM_SANITIZERS "undefined")
endif()

View file

@ -9,6 +9,9 @@
#include <zephyr/kernel.h>
#include <string.h>
#include "heap.h"
#ifdef CONFIG_MSAN
#include <sanitizer/msan_interface.h>
#endif
#ifdef CONFIG_SYS_HEAP_RUNTIME_STATS
static inline void increase_allocated_bytes(struct z_heap *h, size_t num_bytes)
@ -291,6 +294,7 @@ void *sys_heap_alloc(struct sys_heap *heap, size_t bytes)
chunksz_to_bytes(h, chunk_size(h, c)));
#endif
IF_ENABLED(CONFIG_MSAN, (__msan_allocated_memory(mem, bytes)));
return mem;
}
@ -358,6 +362,7 @@ void *sys_heap_aligned_alloc(struct sys_heap *heap, size_t align, size_t bytes)
}
set_chunk_used(h, c, true);
#ifdef CONFIG_SYS_HEAP_RUNTIME_STATS
increase_allocated_bytes(h, chunksz_to_bytes(h, chunk_size(h, c)));
#endif
@ -367,6 +372,7 @@ void *sys_heap_aligned_alloc(struct sys_heap *heap, size_t align, size_t bytes)
chunksz_to_bytes(h, chunk_size(h, c)));
#endif
IF_ENABLED(CONFIG_MSAN, (__msan_allocated_memory(mem, bytes)));
return mem;
}
@ -478,6 +484,8 @@ void *sys_heap_aligned_realloc(struct sys_heap *heap, void *ptr,
void sys_heap_init(struct sys_heap *heap, void *mem, size_t bytes)
{
IF_ENABLED(CONFIG_MSAN, (__sanitizer_dtor_callback(mem, bytes)));
if (IS_ENABLED(CONFIG_SYS_HEAP_SMALL_ONLY)) {
/* Must fit in a 15 bit count of HUNK_UNIT */
__ASSERT(bytes / CHUNK_UNIT <= 0x7fffU, "heap size is too big");

View file

@ -154,6 +154,18 @@ config UBSAN
architecture, and requires a recent-ish compiler with the
``-fsanitize=undefined`` command line option.
config MSAN
bool "Build with memory sanitizer"
depends on ARCH_POSIX
help
Builds Zephyr with the LLVM MemorySanitizer enabled. Works
only on the posix architecture currently, and only with host
compilers recent enough to support the feature (currently
clang on x86_64 only). It cannot be used in tandem with
CONFIG_ASAN due to clang limitations. You must choose one
or the other (but can combine it with CONFIG_UBSAN if you
like)
config STACK_USAGE
bool "Generate stack usage information"
help