diff options
author | Jens Wiklander <jens.wiklander@linaro.org> | 2016-08-30 14:02:25 +0200 |
---|---|---|
committer | Jens Wiklander <jens.wiklander@linaro.org> | 2016-09-08 10:09:50 +0200 |
commit | 1d171f95db3ea1187f5ff0ae98c49ce400fc8eb6 (patch) | |
tree | b2b932a5922d2adf4e9fa572bd9fe5f703d95365 | |
parent | b18dfc622d4b24249738fdc48257b1ab9bd1f12f (diff) |
core: add support for kernel address sanitizer
Adds support for kernel address sanitizer.
Currently only for plat-vexpress-qemu_virt.
Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org>
Tested-by: Jens Wiklander <jens.wiklander@linaro.org> (QEMU v7)
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
-rw-r--r-- | core/arch/arm/arm.mk | 5 | ||||
-rw-r--r-- | core/arch/arm/include/kernel/generic_boot.h | 19 | ||||
-rw-r--r-- | core/arch/arm/kernel/generic_boot.c | 61 | ||||
-rw-r--r-- | core/arch/arm/kernel/generic_entry_a32.S | 27 | ||||
-rw-r--r-- | core/arch/arm/kernel/kern.ld.S | 25 | ||||
-rw-r--r-- | core/arch/arm/kernel/thread.c | 10 | ||||
-rw-r--r-- | core/arch/arm/plat-vexpress/conf.mk | 10 | ||||
-rw-r--r-- | core/arch/arm/tee/init.c | 2 | ||||
-rw-r--r-- | core/core.mk | 10 | ||||
-rw-r--r-- | core/include/kernel/asan.h | 61 | ||||
-rw-r--r-- | core/kernel/asan.c | 271 | ||||
-rw-r--r-- | core/kernel/sub.mk | 2 | ||||
-rw-r--r-- | lib/libutils/isoc/bget.c | 8 | ||||
-rw-r--r-- | lib/libutils/isoc/bget_malloc.c | 33 | ||||
-rw-r--r-- | lib/libutils/isoc/include/malloc.h | 2 | ||||
-rw-r--r-- | lib/libutils/isoc/malloc_lock.c | 36 | ||||
-rw-r--r-- | lib/libutils/isoc/sub.mk | 4 | ||||
-rw-r--r-- | mk/config.mk | 7 |
18 files changed, 575 insertions, 18 deletions
diff --git a/core/arch/arm/arm.mk b/core/arch/arm/arm.mk index b9528325..7d3c04a5 100644 --- a/core/arch/arm/arm.mk +++ b/core/arch/arm/arm.mk @@ -22,6 +22,11 @@ platform-hard-float-enabled := y endif endif +ifeq ($(CFG_WITH_PAGER),y) +ifeq ($(CFG_CORE_SANITIZE_KADDRESS),y) +$(error Error: CFG_CORE_SANITIZE_KADDRESS not compatible with CFG_WITH_PAGER) +endif +endif core-platform-cppflags += -I$(arch-dir)/include core-platform-subdirs += \ diff --git a/core/arch/arm/include/kernel/generic_boot.h b/core/arch/arm/include/kernel/generic_boot.h index 8d8d4a84..61b27f5c 100644 --- a/core/arch/arm/include/kernel/generic_boot.h +++ b/core/arch/arm/include/kernel/generic_boot.h @@ -27,7 +27,8 @@ #ifndef KERNEL_GENERIC_BOOT_H #define KERNEL_GENERIC_BOOT_H -#include <stdint.h> +#include <initcall.h> +#include <types_ext.h> #if defined(CFG_WITH_ARM_TRUSTED_FW) unsigned long cpu_on_handler(unsigned long a0, unsigned long a1); @@ -47,10 +48,21 @@ void init_sec_mon(unsigned long nsec_entry); const struct thread_handlers *generic_boot_get_handlers(void); extern uint8_t __text_init_start[]; +extern uint8_t __text_start[]; +extern initcall_t __initcall_start; +extern initcall_t __initcall_end; extern uint8_t __data_start[]; extern uint8_t __data_end[]; +extern uint8_t __rodata_start[]; +extern uint8_t __rodata_end[]; +extern uint8_t __early_bss_start[]; +extern uint8_t __early_bss_end[]; extern uint8_t __bss_start[]; extern uint8_t __bss_end[]; +extern uint8_t __nozi_start[]; +extern uint8_t __nozi_end[]; +extern uint8_t __nozi_stack_start[]; +extern uint8_t __nozi_stack_end[]; extern uint8_t __init_start[]; extern uint8_t __init_size[]; extern uint8_t __tmp_hashes_start[]; @@ -63,6 +75,11 @@ extern uint8_t __pageable_part_start[]; extern uint8_t __pageable_part_end[]; extern uint8_t __pageable_start[]; extern uint8_t __pageable_end[]; +extern uint8_t __asan_shadow_start[]; +extern uint8_t __asan_shadow_end[]; +extern vaddr_t __ctor_list; +extern vaddr_t __ctor_end; +extern uint8_t __end[]; /* Generated by core/arch/arm/kernel/link.mk */ extern const char core_v_str[]; diff --git a/core/arch/arm/kernel/generic_boot.c b/core/arch/arm/kernel/generic_boot.c index 50a43dde..29263920 100644 --- a/core/arch/arm/kernel/generic_boot.c +++ b/core/arch/arm/kernel/generic_boot.c @@ -33,6 +33,7 @@ #include <kernel/thread.h> #include <kernel/panic.h> #include <kernel/misc.h> +#include <kernel/asan.h> #include <malloc.h> #include <mm/core_mmu.h> #include <mm/core_memprot.h> @@ -324,6 +325,65 @@ static void init_runtime(unsigned long pageable_part) } #else + +#ifdef CFG_CORE_SANITIZE_KADDRESS +static void init_run_constructors(void) +{ + vaddr_t *ctor; + + for (ctor = &__ctor_list; ctor < &__ctor_end; ctor++) + ((void (*)(void))(*ctor))(); +} + +static void init_asan(void) +{ + + /* + * CFG_ASAN_SHADOW_OFFSET is also supplied as + * -fasan-shadow-offset=$(CFG_ASAN_SHADOW_OFFSET) to the compiler. + * Since all the needed values to calculate the value of + * CFG_ASAN_SHADOW_OFFSET isn't available in to make we need to + * calculate it in advance and hard code it into the platform + * conf.mk. Here where we have all the needed values we double + * check that the compiler is supplied the correct value. + */ + +#define __ASAN_SHADOW_START \ + ROUNDUP(CFG_TEE_RAM_START + (CFG_TEE_RAM_VA_SIZE * 8) / 9 - 8, 8) + assert(__ASAN_SHADOW_START == (vaddr_t)&__asan_shadow_start); +#define __CFG_ASAN_SHADOW_OFFSET \ + (__ASAN_SHADOW_START - (CFG_TEE_RAM_START / 8)) + COMPILE_TIME_ASSERT(CFG_ASAN_SHADOW_OFFSET == __CFG_ASAN_SHADOW_OFFSET); +#undef __ASAN_SHADOW_START +#undef __CFG_ASAN_SHADOW_OFFSET + + /* + * Assign area covered by the shadow area, everything from start up + * to the beginning of the shadow area. + */ + asan_set_shadowed((void *)CFG_TEE_LOAD_ADDR, &__asan_shadow_start); + + /* + * Add access to areas that aren't opened automatically by a + * constructor. + */ + asan_tag_access(&__initcall_start, &__initcall_end); + asan_tag_access(&__ctor_list, &__ctor_end); + asan_tag_access(__rodata_start, __rodata_end); + asan_tag_access(__early_bss_start, __early_bss_end); + asan_tag_access(__nozi_start, __nozi_end); + + init_run_constructors(); + + /* Everything is tagged correctly, let's start address sanitizing. */ + asan_start(); +} +#else /*CFG_CORE_SANITIZE_KADDRESS*/ +static void init_asan(void) +{ +} +#endif /*CFG_CORE_SANITIZE_KADDRESS*/ + static void init_runtime(unsigned long pageable_part __unused) { /* @@ -335,6 +395,7 @@ static void init_runtime(unsigned long pageable_part __unused) thread_init_boot_thread(); + init_asan(); malloc_add_pool(__heap1_start, __heap1_end - __heap1_start); /* diff --git a/core/arch/arm/kernel/generic_entry_a32.S b/core/arch/arm/kernel/generic_entry_a32.S index 85ce3d76..8deeb036 100644 --- a/core/arch/arm/kernel/generic_entry_a32.S +++ b/core/arch/arm/kernel/generic_entry_a32.S @@ -34,6 +34,7 @@ #include <sm/teesmc_opteed_macros.h> #include <sm/teesmc_opteed.h> #include <kernel/unwind.h> +#include <kernel/asan.h> .section .data .balign 4 @@ -250,6 +251,32 @@ copy_init: bgt copy_init #endif + +#ifdef CFG_CORE_SANITIZE_KADDRESS + /* First initialize the entire shadow area with no access */ + ldr r0, =__asan_shadow_start /* start */ + ldr r1, =__asan_shadow_end /* limit */ + mov r2, #ASAN_DATA_RED_ZONE +shadow_no_access: + str r2, [r0], #4 + cmp r0, r1 + bls shadow_no_access + + /* Mark the entire stack area as OK */ + ldr r2, =CFG_ASAN_SHADOW_OFFSET + ldr r0, =__nozi_stack_start /* start */ + lsr r0, r0, #ASAN_BLOCK_SHIFT + add r0, r0, r2 + ldr r1, =__nozi_stack_end /* limit */ + lsr r1, r1, #ASAN_BLOCK_SHIFT + add r1, r1, r2 + mov r2, #0 +shadow_stack_access_ok: + strb r2, [r0], #1 + cmp r0, r1 + bls shadow_stack_access_ok +#endif + set_sp /* complete ARM secure MP common configuration */ diff --git a/core/arch/arm/kernel/kern.ld.S b/core/arch/arm/kernel/kern.ld.S index 486d1cbb..67e5f6df 100644 --- a/core/arch/arm/kernel/kern.ld.S +++ b/core/arch/arm/kernel/kern.ld.S @@ -166,14 +166,14 @@ SECTIONS . = ALIGN(4); } - .ctors : ALIGN(4) { + .ctors : ALIGN(8) { __ctor_list = .; - *(.ctors) + KEEP(*(.ctors .ctors.* .init_array .init_array.*)) __ctor_end = .; } - .dtors : ALIGN(4) { + .dtors : ALIGN(8) { __dtor_list = .; - *(.dtors) + KEEP(*(.dtors .dtors.* .fini_array .fini_array.*)) __dtor_end = .; } .got : { *(.got.plt) *(.got) } @@ -211,7 +211,14 @@ SECTIONS * L1 mmu table requires 16 KiB alignment */ .nozi (NOLOAD) : ALIGN(16 * 1024) { + __nozi_start = .; KEEP(*(.nozi .nozi.*)) + . = ALIGN(16); + __nozi_end = .; + __nozi_stack_start = .; + KEEP(*(.nozi_stack)) + . = ALIGN(8); + __nozi_stack_end = .; } #ifdef CFG_WITH_PAGER @@ -304,6 +311,16 @@ SECTIONS #endif /*CFG_WITH_PAGER*/ +#ifdef CFG_CORE_SANITIZE_KADDRESS + . = CFG_TEE_RAM_START + (CFG_TEE_RAM_VA_SIZE * 8) / 9 - 8; + . = ALIGN(8); + .asan_shadow : { + __asan_shadow_start = .; + . += CFG_TEE_RAM_VA_SIZE / 9; + __asan_shadow_end = .; + } +#endif /*CFG_CORE_SANITIZE_KADDRESS*/ + __end = .; #ifndef CFG_WITH_PAGER diff --git a/core/arch/arm/kernel/thread.c b/core/arch/arm/kernel/thread.c index c13bf5aa..1fc25014 100644 --- a/core/arch/arm/kernel/thread.c +++ b/core/arch/arm/kernel/thread.c @@ -53,11 +53,19 @@ #include "thread_private.h" #ifdef ARM32 +#ifdef CFG_CORE_SANITIZE_KADDRESS +#define STACK_TMP_SIZE 3072 +#else #define STACK_TMP_SIZE 1024 +#endif #define STACK_THREAD_SIZE 8192 #if TRACE_LEVEL > 0 +#ifdef CFG_CORE_SANITIZE_KADDRESS +#define STACK_ABT_SIZE 3072 +#else #define STACK_ABT_SIZE 2048 +#endif #else #define STACK_ABT_SIZE 1024 #endif @@ -101,7 +109,7 @@ static struct thread_core_local thread_core_local[CFG_TEE_CORE_NB_CORE]; linkage uint32_t name[num_stacks] \ [ROUNDUP(stack_size + STACK_CANARY_SIZE, STACK_ALIGNMENT) / \ sizeof(uint32_t)] \ - __attribute__((section(".nozi.stack"), \ + __attribute__((section(".nozi_stack"), \ aligned(STACK_ALIGNMENT))) #define STACK_SIZE(stack) (sizeof(stack) - STACK_CANARY_SIZE / 2) diff --git a/core/arch/arm/plat-vexpress/conf.mk b/core/arch/arm/plat-vexpress/conf.mk index 816553dc..f4037d57 100644 --- a/core/arch/arm/plat-vexpress/conf.mk +++ b/core/arch/arm/plat-vexpress/conf.mk @@ -54,9 +54,17 @@ ifeq ($(PLATFORM_FLAVOR),juno) CFG_CRYPTO_WITH_CE ?= y endif -# SE API is only supported by QEMU Virt platform ifeq ($(PLATFORM_FLAVOR),qemu_virt) +ifeq ($(CFG_CORE_SANITIZE_KADDRESS),y) +# CFG_ASAN_SHADOW_OFFSET is calculated as: +# (&__asan_shadow_start - (CFG_TEE_RAM_START / 8) +# This is unfortunately currently not possible to do in make so we have to +# calculate it offline, there's some asserts in +# core/arch/arm/kernel/generic_boot.c to check that we got it right +CFG_ASAN_SHADOW_OFFSET=0x6e4038e0 +endif $(call force,CFG_DT,y) +# SE API is only supported by QEMU Virt platform CFG_SE_API ?= y CFG_SE_API_SELF_TEST ?= y CFG_PCSC_PASSTHRU_READER_DRV ?= y diff --git a/core/arch/arm/tee/init.c b/core/arch/arm/tee/init.c index 68a714ec..66d2a2bc 100644 --- a/core/arch/arm/tee/init.c +++ b/core/arch/arm/tee/init.c @@ -33,6 +33,7 @@ #include <mm/core_memprot.h> #include <trace.h> #include <kernel/time_source.h> +#include <kernel/generic_boot.h> #include <mm/tee_mmu.h> #include <tee/tee_fs.h> #include <tee/tee_cryp_provider.h> @@ -42,7 +43,6 @@ #define TEE_MON_MAX_NUM_ARGS 8 -extern initcall_t __initcall_start, __initcall_end; static void call_initcalls(void) { initcall_t *call; diff --git a/core/core.mk b/core/core.mk index afce7eaf..222d5bfc 100644 --- a/core/core.mk +++ b/core/core.mk @@ -28,6 +28,16 @@ cflags$(sm) += $(core-platform-cflags) ifeq ($(CFG_CORE_SANITIZE_UNDEFINED),y) cflags$(sm) += -fsanitize=undefined endif +ifeq ($(CFG_CORE_SANITIZE_KADDRESS),y) +ifeq ($(CFG_ASAN_SHADOW_OFFSET),) +$(error error: CFG_CORE_SANITIZE_KADDRESS not supported by platform (flavor)) +endif +cflags_kasan += -fsanitize=kernel-address \ + -fasan-shadow-offset=$(CFG_ASAN_SHADOW_OFFSET)\ + --param asan-stack=1 --param asan-globals=1 \ + --param asan-instrumentation-with-call-threshold=0 +cflags$(sm) += $(cflags_kasan) +endif aflags$(sm) += $(core-platform-aflags) cppflags$(sm) += -DTRACE_LEVEL=$(CFG_TEE_CORE_LOG_LEVEL) diff --git a/core/include/kernel/asan.h b/core/include/kernel/asan.h new file mode 100644 index 00000000..6eaa1191 --- /dev/null +++ b/core/include/kernel/asan.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, Linaro Limited + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __KERNEL_ASAN_H +#define __KERNEL_ASAN_H + + +#define ASAN_DATA_RED_ZONE -1 +#define ASAN_HEAP_RED_ZONE -2 + +#define ASAN_BLOCK_SIZE 8 +#define ASAN_BLOCK_SHIFT 3 +#define ASAN_BLOCK_MASK (ASAN_BLOCK_SIZE - 1) + +#ifndef ASM +#include <types_ext.h> + +void asan_set_shadowed(void *va_begin, void *va_end); +void asan_start(void); + +#ifdef CFG_CORE_SANITIZE_KADDRESS +void asan_tag_no_access(void *begin, void *end); +void asan_tag_access(void *begin, void *end); +void asan_tag_heap_free(void *begin, void *end); +#else +static inline void asan_tag_no_access(void *begin __unused, void *end __unused) +{ +} +static inline void asan_tag_access(void *begin __unused, void *end __unused) +{ +} +static inline void asan_tag_heap_free(void *begin __unused, void *end __unused) +{ +} +#endif + +#endif /*ASM*/ +#endif /*__KERNEL_ASAN_H*/ diff --git a/core/kernel/asan.c b/core/kernel/asan.c new file mode 100644 index 00000000..695f8179 --- /dev/null +++ b/core/kernel/asan.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2016, Linaro Limited + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <compiler.h> +#include <kernel/panic.h> +#include <kernel/asan.h> +#include <string.h> +#include <types_ext.h> +#include <util.h> +#include <trace.h> + +struct asan_source_location { + const char *file_name; + int line_no; + int column_no; +}; + +struct asan_global { + uintptr_t beg; + uintptr_t size; + uintptr_t size_with_redzone; + const char *name; + const char *module_name; + uintptr_t has_dynamic_init; + struct asan_source_location *location; +}; + +static vaddr_t asan_va_base; +static size_t asan_va_size; +static bool asan_active; + +static int8_t *va_to_shadow(void *va) +{ + vaddr_t sa = ((vaddr_t)va / ASAN_BLOCK_SIZE) + CFG_ASAN_SHADOW_OFFSET; + + return (int8_t *)sa; +} + +static size_t va_range_to_shadow_size(void *begin, void *end) +{ + return ((vaddr_t)end - (vaddr_t)begin) / ASAN_BLOCK_SIZE; +} + +static bool va_range_inside_shadow(void *begin, void *end) +{ + vaddr_t b = (vaddr_t)begin; + vaddr_t e = (vaddr_t)end; + + if (b >= e) + return false; + return (b >= asan_va_base) && (e <= (asan_va_base + asan_va_size)); +} + +static bool va_range_outside_shadow(void *begin, void *end) +{ + vaddr_t b = (vaddr_t)begin; + vaddr_t e = (vaddr_t)end; + + if (b >= e) + return false; + return (e <= asan_va_base) || (b >= (asan_va_base + asan_va_size)); +} + +static size_t va_misalignment(void *va) +{ + return (vaddr_t)va & ASAN_BLOCK_MASK; +} + +static bool va_is_well_aligned(void *va) +{ + return !va_misalignment(va); +} + +void asan_set_shadowed(void *begin, void *end) +{ + vaddr_t b = (vaddr_t)begin; + vaddr_t e = (vaddr_t)end; + + assert(!asan_va_base); + assert(va_is_well_aligned(begin)); + assert(va_is_well_aligned(end)); + assert(b < e); + + asan_va_base = b; + asan_va_size = e - b; +} + +void asan_tag_no_access(void *begin, void *end) +{ + assert(va_is_well_aligned(begin)); + 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)); +} + +void asan_tag_access(void *begin, void *end) +{ + if (!asan_va_base) + return; + + 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)); + if (!va_is_well_aligned(end)) + *va_to_shadow(end) = ASAN_BLOCK_SIZE - va_misalignment(end); +} + +void asan_tag_heap_free(void *begin, void *end) +{ + if (!asan_va_base) + return; + + assert(va_range_inside_shadow(begin, 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)); +} + +void asan_start(void) +{ + assert(asan_va_base && !asan_active); + asan_active = true; +} + +static void check_access(vaddr_t addr, size_t size) +{ + void *begin = (void *)addr; + void *end = (void *)(addr + size); + int8_t *a; + int8_t *e; + + if (!asan_active || !size) + return; + if (va_range_outside_shadow(begin, end)) + return; + /* + * If it isn't outside it has to be completely inside or there's a + * problem. + */ + if (!va_range_inside_shadow(begin, end)) + panic(); + + e = va_to_shadow(end); + for (a = va_to_shadow(begin); a != e; a++) + if (*a < 0) + panic(); + + if (!va_is_well_aligned(end) && + va_misalignment(end) > (size_t)(*e - ASAN_BLOCK_SIZE)) + panic(); +} + +static void check_load(vaddr_t addr, size_t size) +{ + check_access(addr, size); +} + +static void check_store(vaddr_t addr, size_t size) +{ + check_access(addr, size); +} + +static void __noreturn report_load(vaddr_t addr __unused, size_t size __unused) +{ + panic(); +} + +static void __noreturn report_store(vaddr_t addr __unused, size_t size __unused) +{ + panic(); +} + + + +#define DEFINE_ASAN_FUNC(type, size) \ + void __asan_##type##size(vaddr_t addr); \ + void __asan_##type##size(vaddr_t addr) \ + { check_##type(addr, size); } \ + void __asan_##type##size##_noabort(vaddr_t addr); \ + void __asan_##type##size##_noabort(vaddr_t addr) \ + { check_##type(addr, size); } \ + void __asan_report_##type##size##_noabort(vaddr_t addr);\ + void __noreturn __asan_report_##type##size##_noabort(vaddr_t addr) \ + { report_##type(addr, size); } + +DEFINE_ASAN_FUNC(load, 1) +DEFINE_ASAN_FUNC(load, 2) +DEFINE_ASAN_FUNC(load, 4) +DEFINE_ASAN_FUNC(load, 8) +DEFINE_ASAN_FUNC(load, 16) +DEFINE_ASAN_FUNC(store, 1) +DEFINE_ASAN_FUNC(store, 2) +DEFINE_ASAN_FUNC(store, 4) +DEFINE_ASAN_FUNC(store, 8) +DEFINE_ASAN_FUNC(store, 16) + +void __asan_loadN_noabort(vaddr_t addr, size_t size); +void __asan_loadN_noabort(vaddr_t addr, size_t size) +{ + check_load(addr, size); +} + +void __asan_storeN_noabort(vaddr_t addr, size_t size); +void __asan_storeN_noabort(vaddr_t addr, size_t size) +{ + check_store(addr, size); +} + +void __asan_report_load_n_noabort(vaddr_t addr, size_t size); +void __noreturn __asan_report_load_n_noabort(vaddr_t addr, size_t size) +{ + report_load(addr, size); +} + +void __asan_report_store_n_noabort(vaddr_t addr, size_t size); +void __noreturn __asan_report_store_n_noabort(vaddr_t addr, size_t size) +{ + report_store(addr, size); +} + +void __asan_handle_no_return(void); +void __noreturn __asan_handle_no_return(void) +{ + panic(); +} + +void __asan_register_globals(struct asan_global *globals, size_t size); +void __asan_register_globals(struct asan_global *globals, size_t size) +{ + size_t n; + + for (n = 0; n < size; n++) + asan_tag_access((void *)globals[n].beg, + (void *)(globals[n].beg + globals[n].size)); +} + +void __asan_unregister_globals(struct asan_global *globals, size_t size); +void __asan_unregister_globals(struct asan_global *globals __unused, + size_t size __unused) +{ +} diff --git a/core/kernel/sub.mk b/core/kernel/sub.mk index e0de88d3..4b34f9cf 100644 --- a/core/kernel/sub.mk +++ b/core/kernel/sub.mk @@ -6,3 +6,5 @@ srcs-y += panic.c srcs-y += handle.c srcs-y += interrupt.c srcs-$(CFG_CORE_SANITIZE_UNDEFINED) += ubsan.c +srcs-$(CFG_CORE_SANITIZE_KADDRESS) += asan.c +cflags-remove-asan.c-y += $(cflags_kasan) diff --git a/lib/libutils/isoc/bget.c b/lib/libutils/isoc/bget.c index dddb464f..99ce12a4 100644 --- a/lib/libutils/isoc/bget.c +++ b/lib/libutils/isoc/bget.c @@ -657,6 +657,7 @@ void *bget(requested_size) numget++; /* Increment number of bget() calls */ #endif buf = (void *) ((((char *) ba) + sizeof(struct bhead))); + tag_asan_alloced(buf, size); return buf; } else { struct bhead *ba; @@ -685,6 +686,7 @@ void *bget(requested_size) /* Give user buffer starting at queue links. */ buf = (void *) &(b->ql); + tag_asan_alloced(buf, size); return buf; } } @@ -727,6 +729,7 @@ void *bget(requested_size) numdget++; /* Direct bget() call count */ #endif buf = (void *) (bdh + 1); + tag_asan_alloced(buf, size); return buf; } @@ -825,6 +828,7 @@ void brel(buf) void *buf; { struct bfhead *b, *bn; + bufsize bs; b = BFH(((char *) buf) - sizeof(struct bhead)); #ifdef BufStats @@ -847,8 +851,10 @@ void brel(buf) V memset((char *) buf, 0x55, (MemSize) (bdh->tsize - sizeof(struct bdhead))); #endif /* FreeWipe */ + bs = bdh->tsize - sizeof(struct bdhead); assert(relfcn != NULL); (*relfcn)((void *) bdh); /* Release it directly. */ + tag_asan_free(buf, bs); return; } #endif /* BECtl */ @@ -860,6 +866,7 @@ void brel(buf) bn = NULL; } assert(b->bh.bsize < 0); + bs = -b->bh.bsize; /* Back pointer in next buffer must be zero, indicating the same thing: */ @@ -964,6 +971,7 @@ void brel(buf) #endif /* BufStats */ } #endif /* BECtl */ + tag_asan_free(buf, bs); } #ifdef BECtl diff --git a/lib/libutils/isoc/bget_malloc.c b/lib/libutils/isoc/bget_malloc.c index 20b61612..932c36f8 100644 --- a/lib/libutils/isoc/bget_malloc.c +++ b/lib/libutils/isoc/bget_malloc.c @@ -104,24 +104,32 @@ #include <stdint.h> #include <stdbool.h> #include <malloc.h> -#include "bget.c" /* this is ugly, but this is bget */ #include <util.h> #include <trace.h> -#ifdef __KERNEL__ +#if defined(__KERNEL__) /* Compiling for TEE Core */ +#include <kernel/asan.h> #include <kernel/mutex.h> -static struct mutex malloc_mu = MUTEX_INITIALIZER; - static void malloc_lock(void) { - mutex_lock(&malloc_mu); + mutex_lock(&__malloc_mu); } static void malloc_unlock(void) { - mutex_unlock(&malloc_mu); + mutex_unlock(&__malloc_mu); +} + +static void tag_asan_free(void *buf, size_t len) +{ + asan_tag_heap_free(buf, (uint8_t *)buf + len); +} + +static void tag_asan_alloced(void *buf, size_t len) +{ + asan_tag_access(buf, (uint8_t *)buf + len); } #else /*__KERNEL__*/ @@ -133,11 +141,17 @@ static void malloc_lock(void) static void malloc_unlock(void) { } + +static void tag_asan_free(void *buf __unused, size_t len __unused) +{ +} + +static void tag_asan_alloced(void *buf __unused, size_t len __unused) +{ +} #endif /*__KERNEL__*/ -#if defined(ENABLE_MDBG) -#include <trace.h> -#endif +#include "bget.c" /* this is ugly, but this is bget */ struct malloc_pool { void *buf; @@ -894,6 +908,7 @@ void malloc_add_pool(void *buf, size_t len) } malloc_lock(); + tag_asan_free((void *)start, end - start); bpool((void *)start, end - start); l = malloc_pool_len + 1; p = realloc_unlocked(malloc_pool, sizeof(struct malloc_pool) * l); diff --git a/lib/libutils/isoc/include/malloc.h b/lib/libutils/isoc/include/malloc.h index d65dc2f4..0fac3c83 100644 --- a/lib/libutils/isoc/include/malloc.h +++ b/lib/libutils/isoc/include/malloc.h @@ -30,6 +30,8 @@ #include <stddef.h> #include <types_ext.h> +extern struct mutex __malloc_mu; + void free(void *ptr); #ifdef ENABLE_MDBG diff --git a/lib/libutils/isoc/malloc_lock.c b/lib/libutils/isoc/malloc_lock.c new file mode 100644 index 00000000..97058d2d --- /dev/null +++ b/lib/libutils/isoc/malloc_lock.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016, Linaro Limited + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <malloc.h> + +#ifdef __KERNEL__ +/* Compiling for TEE Core */ +#include <kernel/mutex.h> + +struct mutex __malloc_mu = MUTEX_INITIALIZER; + +#endif /*__KERNEL__*/ diff --git a/lib/libutils/isoc/sub.mk b/lib/libutils/isoc/sub.mk index 1ee13b84..925cb48f 100644 --- a/lib/libutils/isoc/sub.mk +++ b/lib/libutils/isoc/sub.mk @@ -3,6 +3,10 @@ global-incdirs-y += include srcs-y += bget_malloc.c cflags-remove-bget_malloc.c-y += -Wold-style-definition -Wredundant-decls cflags-bget_malloc.c-y += -Wno-sign-compare -Wno-cast-align +ifeq ($(sm),core) +cflags-remove-bget_malloc.c-y += $(cflags_kasan) +endif +srcs-y += malloc_lock.c srcs-y += snprintf.c diff --git a/mk/config.mk b/mk/config.mk index 657969ba..68beea34 100644 --- a/mk/config.mk +++ b/mk/config.mk @@ -168,9 +168,14 @@ CFG_WITH_USER_TA ?= y CFG_SMALL_PAGE_USER_TA ?= y # Enable support for detected undefined behavior in C -# Uses a log of memory, can't be enabled by default +# Uses a lot of memory, can't be enabled by default CFG_CORE_SANITIZE_UNDEFINED ?= n +# Enable Kernel Address sanitizer, has a huge performance impact, uses a +# lot of memory and need platform specific adaptations, can't be enabled by +# default +CFG_CORE_SANITIZE_KADDRESS ?= n + # Device Tree support # When enabled, the TEE _start function expects to find the address of a # Device Tree Blob (DTB) in register r2. The DT parsing code relies on |