aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Wiklander <jens.wiklander@linaro.org>2016-08-30 14:02:25 +0200
committerJens Wiklander <jens.wiklander@linaro.org>2016-09-08 10:09:50 +0200
commit1d171f95db3ea1187f5ff0ae98c49ce400fc8eb6 (patch)
treeb2b932a5922d2adf4e9fa572bd9fe5f703d95365
parentb18dfc622d4b24249738fdc48257b1ab9bd1f12f (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.mk5
-rw-r--r--core/arch/arm/include/kernel/generic_boot.h19
-rw-r--r--core/arch/arm/kernel/generic_boot.c61
-rw-r--r--core/arch/arm/kernel/generic_entry_a32.S27
-rw-r--r--core/arch/arm/kernel/kern.ld.S25
-rw-r--r--core/arch/arm/kernel/thread.c10
-rw-r--r--core/arch/arm/plat-vexpress/conf.mk10
-rw-r--r--core/arch/arm/tee/init.c2
-rw-r--r--core/core.mk10
-rw-r--r--core/include/kernel/asan.h61
-rw-r--r--core/kernel/asan.c271
-rw-r--r--core/kernel/sub.mk2
-rw-r--r--lib/libutils/isoc/bget.c8
-rw-r--r--lib/libutils/isoc/bget_malloc.c33
-rw-r--r--lib/libutils/isoc/include/malloc.h2
-rw-r--r--lib/libutils/isoc/malloc_lock.c36
-rw-r--r--lib/libutils/isoc/sub.mk4
-rw-r--r--mk/config.mk7
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