From 73fa5037abf63f9c9b5630e9288f1b8335509bb3 Mon Sep 17 00:00:00 2001 From: Jens Wiklander Date: Mon, 11 Sep 2017 11:39:24 +0200 Subject: [PATCH 1/4] core: asan: provide asan_memset_unchecked() Provides asan_memset_unchecked() which does a memset that isn't checked against the tagging in the ASAN shadow area. If ASAN isn't enabled it's replaced by a direct call to memset(). Reviewed-by: Etienne Carriere Signed-off-by: Jens Wiklander --- core/include/kernel/asan.h | 8 ++++++++ core/kernel/asan.c | 22 +++++++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/core/include/kernel/asan.h b/core/include/kernel/asan.h index 36a362aac2a..121a935667c 100644 --- a/core/include/kernel/asan.h +++ b/core/include/kernel/asan.h @@ -36,6 +36,7 @@ #define ASAN_BLOCK_MASK (ASAN_BLOCK_SIZE - 1) #ifndef ASM +#include #include void asan_set_shadowed(const void *va_begin, const void *va_end); @@ -45,6 +46,7 @@ void asan_start(void); void asan_tag_no_access(const void *begin, const void *end); void asan_tag_access(const void *begin, const void *end); void asan_tag_heap_free(const void *begin, const void *end); +void *asan_memset_unchecked(void *s, int c, size_t n); #else static inline void asan_tag_no_access(const void *begin __unused, const void *end __unused) @@ -58,6 +60,12 @@ static inline void asan_tag_heap_free(const void *begin __unused, const void *end __unused) { } + +static inline void *asan_memset_unchecked(void *s, int c, size_t n) +{ + return memset(s, c, n); +} + #endif #endif /*ASM*/ diff --git a/core/kernel/asan.c b/core/kernel/asan.c index 6d5baea1057..86dff1babf7 100644 --- a/core/kernel/asan.c +++ b/core/kernel/asan.c @@ -116,8 +116,8 @@ void asan_tag_no_access(const void *begin, const void *end) assert(va_is_well_aligned(end)); assert(va_range_inside_shadow(begin, end)); - memset(va_to_shadow(begin), ASAN_DATA_RED_ZONE, - va_range_to_shadow_size(begin, end)); + asan_memset_unchecked(va_to_shadow(begin), ASAN_DATA_RED_ZONE, + va_range_to_shadow_size(begin, end)); } void asan_tag_access(const void *begin, const void *end) @@ -128,7 +128,8 @@ void asan_tag_access(const void *begin, const void *end) assert(va_range_inside_shadow(begin, end)); assert(va_is_well_aligned(begin)); - memset(va_to_shadow(begin), 0, va_range_to_shadow_size(begin, end)); + asan_memset_unchecked(va_to_shadow(begin), 0, + va_range_to_shadow_size(begin, end)); if (!va_is_well_aligned(end)) *va_to_shadow(end) = ASAN_BLOCK_SIZE - va_misalignment(end); } @@ -142,8 +143,19 @@ void asan_tag_heap_free(const void *begin, const void *end) assert(va_is_well_aligned(begin)); assert(va_is_well_aligned(end)); - memset(va_to_shadow(begin), ASAN_HEAP_RED_ZONE, - va_range_to_shadow_size(begin, end)); + asan_memset_unchecked(va_to_shadow(begin), ASAN_HEAP_RED_ZONE, + va_range_to_shadow_size(begin, end)); +} + +void *asan_memset_unchecked(void *s, int c, size_t n) +{ + uint8_t *b = s; + size_t m; + + for (m = 0; m < n; m++) + b[m] = c; + + return s; } void asan_start(void) From e870b9e61212a17f35c69fc0d7d806aae98eae74 Mon Sep 17 00:00:00 2001 From: Jens Wiklander Date: Mon, 11 Sep 2017 11:42:41 +0200 Subject: [PATCH 2/4] libutils: malloc: use asan_memset_unchecked() The malloc implementation uses the new asan_memset_unchecked() function internally instead of memset() to avoid unexpected asserts when the address sanitizer is enabled. bget() tags the requested amount of memory allocated, but eventual padding etc isn't tagged so writes there from instrumented functions, for instance the normal memset(), will be caught. Reviewed-by: Etienne Carriere Signed-off-by: Jens Wiklander --- lib/libutils/isoc/bget.c | 14 +++++++------- lib/libutils/isoc/bget_malloc.c | 20 ++++++++++++++++---- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/lib/libutils/isoc/bget.c b/lib/libutils/isoc/bget.c index 99ce12a4dd0..8199b8b8c8d 100644 --- a/lib/libutils/isoc/bget.c +++ b/lib/libutils/isoc/bget.c @@ -779,7 +779,7 @@ void *bgetz(size) rsize -= sizeof(struct bhead); } assert(rsize >= size); - V memset(buf, 0, (MemSize) rsize); + V memset_unchecked(buf, 0, (MemSize) rsize); } return ((void *) buf); } @@ -848,8 +848,8 @@ void brel(buf) numdrel++; /* Number of direct releases */ #endif /* BufStats */ #ifdef FreeWipe - V memset((char *) buf, 0x55, - (MemSize) (bdh->tsize - sizeof(struct bdhead))); + V memset_unchecked((char *) buf, 0x55, + (MemSize) (bdh->tsize - sizeof(struct bdhead))); #endif /* FreeWipe */ bs = bdh->tsize - sizeof(struct bdhead); assert(relfcn != NULL); @@ -936,8 +936,8 @@ void brel(buf) bn = BFH(((char *) b) + b->bh.bsize); } #ifdef FreeWipe - V memset(((char *) b) + sizeof(struct bfhead), 0x55, - (MemSize) (b->bh.bsize - sizeof(struct bfhead))); + V memset_unchecked(((char *) b) + sizeof(struct bfhead), 0x55, + (MemSize) (b->bh.bsize - sizeof(struct bfhead))); #endif assert(bn->bh.bsize < 0); @@ -1048,8 +1048,8 @@ void bpool(buf, len) len -= sizeof(struct bhead); b->bh.bsize = (bufsize) len; #ifdef FreeWipe - V memset(((char *) b) + sizeof(struct bfhead), 0x55, - (MemSize) (len - sizeof(struct bfhead))); + V memset_unchecked(((char *) b) + sizeof(struct bfhead), 0x55, + (MemSize) (len - sizeof(struct bfhead))); #endif bn = BH(((char *) b) + len); bn->prevfree = (bufsize) len; diff --git a/lib/libutils/isoc/bget_malloc.c b/lib/libutils/isoc/bget_malloc.c index 552fdaf505c..54a146f48d9 100644 --- a/lib/libutils/isoc/bget_malloc.c +++ b/lib/libutils/isoc/bget_malloc.c @@ -100,12 +100,13 @@ #endif #include -#include -#include -#include #include -#include +#include +#include +#include +#include #include +#include #if defined(__KERNEL__) /* Compiling for TEE Core */ @@ -133,6 +134,11 @@ static void tag_asan_alloced(void *buf, size_t len) asan_tag_access(buf, (uint8_t *)buf + len); } +static void *memset_unchecked(void *s, int c, size_t n) +{ + return asan_memset_unchecked(s, c, n); +} + #else /*__KERNEL__*/ /* Compiling for TA */ static uint32_t malloc_lock(void) @@ -151,6 +157,12 @@ static void tag_asan_free(void *buf __unused, size_t len __unused) static void tag_asan_alloced(void *buf __unused, size_t len __unused) { } + +static void *memset_unchecked(void *s, int c, size_t n) +{ + return memset(s, c, n); +} + #endif /*__KERNEL__*/ #include "bget.c" /* this is ugly, but this is bget */ From b8df824444aeb543e3582113079123f015dbe3ec Mon Sep 17 00:00:00 2001 From: Jens Wiklander Date: Fri, 8 Sep 2017 10:37:57 +0200 Subject: [PATCH 3/4] core: asan: fix check_access() Prior to this patch the for loop in check_access() that checks the access in the shadow area is skipping accesses smaller than a ASAN block (8 bytes). This patch fixes that problem and checks also smaller accesses. Reviewed-by: Etienne Carriere Signed-off-by: Jens Wiklander --- core/kernel/asan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/kernel/asan.c b/core/kernel/asan.c index 86dff1babf7..c10088871cc 100644 --- a/core/kernel/asan.c +++ b/core/kernel/asan.c @@ -182,8 +182,8 @@ static void check_access(vaddr_t addr, size_t size) if (!va_range_inside_shadow(begin, end)) panic(); - e = va_to_shadow(end); - for (a = va_to_shadow(begin); a != e; a++) + e = va_to_shadow((void *)(addr + size - 1)); + for (a = va_to_shadow(begin); a <= e; a++) if (*a < 0) panic(); From 5811b26fd7dd317eff828fea9933cde5e76206a5 Mon Sep 17 00:00:00 2001 From: Jens Wiklander Date: Fri, 8 Sep 2017 10:53:33 +0200 Subject: [PATCH 4/4] core: asan: tag access for .ARM.extab and .ARM.exidx The two sections .ARM.extab and .ARM.exidx are accessed when printing a stack trace. Tag access for these two sections to avoid recursive panics due to failing checks against shadow area. Tested-by: Jens Wiklander (QEMU) Reviewed-by: Etienne Carriere Reviewed-by: Jerome Forissier Signed-off-by: Jens Wiklander --- core/arch/arm/include/kernel/linker.h | 2 ++ core/arch/arm/kernel/generic_boot.c | 2 ++ core/arch/arm/kernel/link_dummy.ld | 2 ++ 3 files changed, 6 insertions(+) diff --git a/core/arch/arm/include/kernel/linker.h b/core/arch/arm/include/kernel/linker.h index 6864e229d62..0639240446c 100644 --- a/core/arch/arm/include/kernel/linker.h +++ b/core/arch/arm/include/kernel/linker.h @@ -45,6 +45,8 @@ */ extern const uint8_t __exidx_start[]; extern const uint8_t __exidx_end[]; +extern const uint8_t __extab_start[]; +extern const uint8_t __extab_end[]; extern const struct pseudo_ta_head __start_ta_head_section; extern const struct pseudo_ta_head __stop_ta_head_section; diff --git a/core/arch/arm/kernel/generic_boot.c b/core/arch/arm/kernel/generic_boot.c index 6a65fa8ce4f..5d97fe67778 100644 --- a/core/arch/arm/kernel/generic_boot.c +++ b/core/arch/arm/kernel/generic_boot.c @@ -346,6 +346,8 @@ static void init_asan(void) asan_tag_access(&__ctor_list, &__ctor_end); asan_tag_access(__rodata_start, __rodata_end); asan_tag_access(__nozi_start, __nozi_end); + asan_tag_access(__exidx_start, __exidx_end); + asan_tag_access(__extab_start, __extab_end); init_run_constructors(); diff --git a/core/arch/arm/kernel/link_dummy.ld b/core/arch/arm/kernel/link_dummy.ld index 4aca773e287..04db03debca 100644 --- a/core/arch/arm/kernel/link_dummy.ld +++ b/core/arch/arm/kernel/link_dummy.ld @@ -47,6 +47,8 @@ __end_phys_nsec_ddr_section = .; __end_phys_sdp_mem_section = .; __exidx_end = .; __exidx_start = .; +__extab_end = .; +__extab_start = .; __heap1_end = .; __heap1_start = .; __heap2_end = .;