[PATCH v3] lib: sbi: Add KASAN support for OpenSBI
Marcos
marcos.oduardo at gmail.com
Wed Mar 18 07:02:20 PDT 2026
Hi,
Ping message. Happy to address any feedback if needed.
El vie, 20 feb 2026 a las 20:33, Marcos Oduardo
(<marcos.oduardo at gmail.com>) escribió:
>
> From: marcos <marcos.oduardo at gmail.com>
>
> KASan (Kernel Address Sanitizer) is a tool implemented using compiler
> instrumentation at runtime that allows checking for memory management
> bugs such as heap OOB access, stack overflow or global OOB write.
> Compiling and testing the OpenSBI firmware against KASan will print a
> message in the console highlighting the memory access that caused the
> bug and its address.
>
> Support for this implementation involves two main components:
>
> 1. The KASan implementation hooks: Custom malloc, memset, memcpy to
> check for bugs and the handlers when finding a bug.
> 2. A test suite to verify correct operation at runtime.
>
> KASan needs to keep a copy of the sanitized memory region. This copy is
> named shadowmap, and each byte of this map corresponds to 8 bytes of
> real memory. KASan keeps a record of the state of each address and
> checks each memory access performed by OpenSBI.
>
> Users may compile OpenSBI with the KASan instrumentation by adding the
> flag ENABLEKASAN=y to the make command. To compile with the tests, add
> the flag ENABLEKASANTESTS=y.
>
> Note that the implementation of KASan adds a certain overhead caused by
> the checks performed at runtime and the shadowmap loaded in memory;
> therefore, it is only expected to be used in development builds, never
> in production. If ENABLEKASAN is not set, no instrumentation is added.
>
> Signed-off-by: Marcos Oduardo <marcos.oduardo at gmail.com>
> ---
> Changes since v2:
> - Relocated shadowmap base address to 0x80100000. Initially, the 0xE7...
> address used was for testing purposes. Upon inspecting OpenSBI memory
> allocation, I determined that the new address is a better placement
> for the shadowmap.
> - Migrated kasan_enabled variable to scratch for HART-independent
> management.
> - Integrated shadow map into OpenSBI domains with PMP protection.
> - Optimized string functions instrumentation in sbi_string.c.
> - KASAN now initializes dynamically, only needing to pass statically
> to the compiler the base address of the shadowmap.
> - KASAN now reports accesses between (fw_start, fw_rw_start] and on
> the shadowmap.
>
> Note on GCC support:
> About the GCC implementation, in order to initialize KASAN dynamically
> a kasan_ignore.txt is passed to Clang via the -fsanitize-ignorelist
> flag. GCC actually doesn't support this functionality, which makes
> the addition a lot harder to implement because you would need to add
> "__attribute__((no_sanitize("address")))" to each function that gets
> called before KASAN initialization. For the time being, I think it is
> better to keep KASAN for GCC unsupported as it would need various
> modifications to the structure of the Makefile itself.
>
> Makefile | 25 ++
> firmware/fw_base.S | 12 +-
> firmware/fw_base.ldS | 9 +-
> include/sbi/sbi_heap.h | 27 +-
> include/sbi/sbi_kasan.h | 26 ++
> include/sbi/sbi_kasan_test.h | 29 ++
> include/sbi/sbi_string.h | 13 +-
> include/sbi/sbi_types.h | 1 +
> kasan_ignore.txt | 14 +
> lib/sbi/objects.mk | 3 +
> lib/sbi/sbi_domain.c | 16 +-
> lib/sbi/sbi_heap.c | 9 +-
> lib/sbi/sbi_init.c | 18 ++
> lib/sbi/sbi_kasan.c | 514 +++++++++++++++++++++++++++++++++++
> lib/sbi/sbi_kasan_test.c | 66 +++++
> lib/sbi/sbi_string.c | 310 +++++++++++++--------
> platform/generic/objects.mk | 3 +-
> 17 files changed, 971 insertions(+), 124 deletions(-)
> create mode 100644 include/sbi/sbi_kasan.h
> create mode 100644 include/sbi/sbi_kasan_test.h
> create mode 100644 kasan_ignore.txt
> create mode 100644 lib/sbi/sbi_kasan.c
> create mode 100644 lib/sbi/sbi_kasan_test.c
>
> diff --git a/Makefile b/Makefile
> index 46541063..890d0874 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -400,6 +400,31 @@ CFLAGS += $(platform-cflags-y)
> CFLAGS += -fPIE -pie
> CFLAGS += $(firmware-cflags-y)
>
> +
> +#KASAN Cflags
> +
> +ifeq ($(ENABLEKASAN),y)
> +KASAN_SHADOW_MEMORY_START := 0x80100000
> +CFLAGS += -DTARGET_ARCH_$(ARCH)
> +CFLAGS += -DKASAN_SHADOW_MEMORY_START=$(KASAN_SHADOW_MEMORY_START)
> +ifeq ($(CC_IS_CLANG),y)
> +KASAN_FLAGS := -fsanitize=kernel-address
> +KASAN_FLAGS += -fno-sanitize-address-use-after-scope
> +KASAN_FLAGS += -DKASAN_ENABLED
> +KASAN_FLAGS += -fsanitize-ignorelist=$(CURDIR)/kasan_ignore.txt
> +KASAN_FLAGS += -mllvm -asan-instrumentation-with-call-threshold=0
> +KASAN_FLAGS += -mllvm -asan-stack=1
> +KASAN_FLAGS += -mllvm -asan-globals=1
> +ifeq ($(ENABLEKASANTESTS),y)
> +KASAN_FLAGS += -DKASAN_TESTS_ENABLED
> +endif
> +CFLAGS += $(KASAN_FLAGS)
> +else
> +$(error OpenSBI KASAN currently requires Clang because GCC is unsupported. Please build with LLVM=y)
> +endif
> +endif
> +
> +
> CPPFLAGS += $(GENFLAGS)
> CPPFLAGS += $(platform-cppflags-y)
> CPPFLAGS += $(firmware-cppflags-y)
> diff --git a/firmware/fw_base.S b/firmware/fw_base.S
> index 63bb4473..8a58d8fe 100644
> --- a/firmware/fw_base.S
> +++ b/firmware/fw_base.S
> @@ -461,22 +461,22 @@ fw_platform_init:
> /* Map implicit memcpy() added by compiler to sbi_memcpy() */
> .section .text
> .align 3
> - .globl memcpy
> -memcpy:
> + .globl __asan_memcpy
> +__asan_memcpy:
> tail sbi_memcpy
>
> /* Map implicit memset() added by compiler to sbi_memset() */
> .section .text
> .align 3
> - .globl memset
> -memset:
> + .globl __asan_memset
> +__asan_memset:
> tail sbi_memset
>
> /* Map implicit memmove() added by compiler to sbi_memmove() */
> .section .text
> .align 3
> - .globl memmove
> -memmove:
> + .globl __asan_memmove
> +__asan_memmove:
> tail sbi_memmove
>
> /* Map implicit memcmp() added by compiler to sbi_memcmp() */
> diff --git a/firmware/fw_base.ldS b/firmware/fw_base.ldS
> index 12c7a844..9619a5a5 100644
> --- a/firmware/fw_base.ldS
> +++ b/firmware/fw_base.ldS
> @@ -39,6 +39,13 @@
> . = ALIGN(8);
> }
>
> + .init_array : /* Needed for KASan - NetBSD style */
> + {
> + __CTOR_LIST__ = .;
> + *(.init_array*)
> + __CTOR_END__ = .;
> + }
> +
> .dynsym :
> {
> *(.dynsym)
> @@ -61,7 +68,7 @@
> * regions, so ensure that the split is power-of-2.
> */
> . = ALIGN(1 << LOG2CEIL((SIZEOF(.rodata) + SIZEOF(.text)
> - + SIZEOF(.dynsym) + SIZEOF(.rela.dyn))));
> + + SIZEOF(.dynsym) + SIZEOF(.rela.dyn) + SIZEOF(.init_array))));
>
> PROVIDE(_fw_rw_start = .);
>
> diff --git a/include/sbi/sbi_heap.h b/include/sbi/sbi_heap.h
> index a4b3f0c6..299a0985 100644
> --- a/include/sbi/sbi_heap.h
> +++ b/include/sbi/sbi_heap.h
> @@ -11,6 +11,9 @@
> #define __SBI_HEAP_H__
>
> #include <sbi/sbi_types.h>
> +#include <sbi/sbi_kasan.h>
> +#include <sbi/sbi_list.h>
> +#include <sbi/riscv_locks.h>
>
> /* Opaque declaration of heap control struct */
> struct sbi_heap_control;
> @@ -26,11 +29,24 @@ struct sbi_scratch;
> /** Allocate from heap area */
> void *sbi_malloc_from(struct sbi_heap_control *hpctrl, size_t size);
>
> -static inline void *sbi_malloc(size_t size)
> -{
> +#ifdef KASAN_ENABLED
> +static inline void *sbi_malloc(size_t size){
> + return kasan_malloc_hook(&global_hpctrl, size);
> +}
> +
> +static inline void *zalloc_from (struct sbi_heap_control *hpctrl, size_t size){ //function needed for KASAn integration in compile options
> + return kasan_malloc_hook(hpctrl, size);
> +}
> +#else
> +static inline void *zalloc_from (struct sbi_heap_control *hpctrl, size_t size){
> return sbi_malloc_from(&global_hpctrl, size);
> }
>
> +static inline void *sbi_malloc(size_t size){
> + return sbi_malloc_from(&global_hpctrl, size);
> +}
> +#endif
> +
> /** Allocate aligned from heap area */
> void *sbi_aligned_alloc_from(struct sbi_heap_control *hpctrl,
> size_t alignment,size_t size);
> @@ -63,10 +79,17 @@ static inline void *sbi_calloc_from(struct sbi_heap_control *hpctrl,
> /** Free-up to heap area */
> void sbi_free_from(struct sbi_heap_control *hpctrl, void *ptr);
>
> +#ifdef KASAN_ENABLED
> +static inline void sbi_free(void *ptr)
> +{
> + return kasan_free_hook(&global_hpctrl, ptr);
> +}
> +#else
> static inline void sbi_free(void *ptr)
> {
> return sbi_free_from(&global_hpctrl, ptr);
> }
> +#endif
>
> /** Amount (in bytes) of free space in the heap area */
> unsigned long sbi_heap_free_space_from(struct sbi_heap_control *hpctrl);
> diff --git a/include/sbi/sbi_kasan.h b/include/sbi/sbi_kasan.h
> new file mode 100644
> index 00000000..93ef9208
> --- /dev/null
> +++ b/include/sbi/sbi_kasan.h
> @@ -0,0 +1,26 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + * Author: Marcos Oduardo <marcos.oduardo at gmail.com>
> + */
> +
> +#ifndef __SBI_KASAN_H__
> +#define __SBI_KASAN_H__
> +
> +#include <sbi/sbi_list.h>
> +#include <sbi/riscv_locks.h>
> +#include <sbi/sbi_scratch.h>
> +#include <sbi/sbi_domain.h>
> +
> +struct heap_node;
> +struct sbi_heap_control;
> +struct sbi_domain_memregion;
> +
> +void kasan_hart_init(struct sbi_scratch *scratch);
> +void kasan_init(struct sbi_scratch *scratch);
> +void *kasan_malloc_hook(struct sbi_heap_control *hpctrl, size_t size);
> +void kasan_free_hook(struct sbi_heap_control *hpctrl, void *ptr);
> +void kasan_shadow_check(unsigned long addr, size_t size, bool write, unsigned long retaddr);
> +void sbi_kasan_get_shadow_region(struct sbi_domain_memregion *reg);
> +unsigned long sbi_kasan_get_shadow_size(void);
> +
> +#endif
> \ No newline at end of file
> diff --git a/include/sbi/sbi_kasan_test.h b/include/sbi/sbi_kasan_test.h
> new file mode 100644
> index 00000000..a7625f3b
> --- /dev/null
> +++ b/include/sbi/sbi_kasan_test.h
> @@ -0,0 +1,29 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + * Author: Marcos Oduardo <marcos.oduardo at gmail.com>
> + */
> +
> +#ifndef __SBI_KASAN_TEST_H__
> +#define __SBI_KASAN_TEST_H__
> +
> +#ifdef KASAN_TESTS_ENABLED
> +
> +#include <sbi/sbi_kasan.h>
> +#include <sbi/sbi_console.h>
> +#include <sbi/sbi_string.h>
> +#include <sbi/sbi_heap.h>
> +
> +typedef void (*global_ctor)(void);
> +
> +// These symbols are defined in the linker script.
> +extern char __global_ctors_start;
> +extern char __global_ctors_end;
> +
> +void call_global_ctors(void);
> +void heap_kasan_test(void);
> +void stack_kasan_test(void);
> +void globals_kasan_test(void);
> +void memset_kasan_test(void);
> +void memcpy_kasan_test(void);
> +#endif
> +#endif
> \ No newline at end of file
> diff --git a/include/sbi/sbi_string.h b/include/sbi/sbi_string.h
> index b7c2bc22..5feab7e6 100644
> --- a/include/sbi/sbi_string.h
> +++ b/include/sbi/sbi_string.h
> @@ -10,6 +10,7 @@
> #ifndef __STRING_H__
> #define __STRING_H__
>
> +#include <sbi/sbi_heap.h>
> #include <sbi/sbi_types.h>
>
> /*
> @@ -27,16 +28,20 @@ size_t sbi_strnlen(const char *str, size_t count);
>
> char *sbi_strcpy(char *dest, const char *src);
>
> +void *sbi_memset(void *s, int c, size_t count);
> +
> +void *sbi_memcpy(void *dest, const void *src, size_t count);
> +#ifdef KASAN_ENABLED
> +void *_real_sbi_memset(void *s, int c, size_t count);
> +
> +void *_real_sbi_memcpy(void *dest, const void *src, size_t count);
> +#endif
> char *sbi_strncpy(char *dest, const char *src, size_t count);
>
> char *sbi_strchr(const char *s, int c);
>
> char *sbi_strrchr(const char *s, int c);
>
> -void *sbi_memset(void *s, int c, size_t count);
> -
> -void *sbi_memcpy(void *dest, const void *src, size_t count);
> -
> void *sbi_memmove(void *dest, const void *src, size_t count);
>
> int sbi_memcmp(const void *s1, const void *s2, size_t count);
> diff --git a/include/sbi/sbi_types.h b/include/sbi/sbi_types.h
> index b8a7e6cb..11ce6eb3 100644
> --- a/include/sbi/sbi_types.h
> +++ b/include/sbi/sbi_types.h
> @@ -14,6 +14,7 @@
>
> /* clang-format off */
>
> +typedef signed char int8_t;
> typedef signed char s8;
> typedef unsigned char u8;
> typedef unsigned char uint8_t;
> diff --git a/kasan_ignore.txt b/kasan_ignore.txt
> new file mode 100644
> index 00000000..e90edf8d
> --- /dev/null
> +++ b/kasan_ignore.txt
> @@ -0,0 +1,14 @@
> +src:*sbi_init.c
> +src:*sbi_domain_context.c
> +src:*sbi_scratch.c
> +src:*sbi_hart.c
> +src:*sbi_trap.c
> +src:*sbi_console.c
> +src:*sbi_kasan.c
> +
> +src:*sbi_string.c
> +
> +src:*fdt*.c
> +
> +src:*platform.c
> +src:*fw_base.S
> diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk
> index 07d13229..34ce07bb 100644
> --- a/lib/sbi/objects.mk
> +++ b/lib/sbi/objects.mk
> @@ -64,6 +64,7 @@ libsbi-objs-$(CONFIG_SBI_ECALL_SSE) += sbi_ecall_sse.o
> carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_MPXY) += ecall_mpxy
> libsbi-objs-$(CONFIG_SBI_ECALL_MPXY) += sbi_ecall_mpxy.o
>
> +
> libsbi-objs-y += sbi_bitmap.o
> libsbi-objs-y += sbi_bitops.o
> libsbi-objs-y += sbi_console.o
> @@ -86,6 +87,8 @@ libsbi-objs-y += sbi_illegal_insn.o
> libsbi-objs-y += sbi_init.o
> libsbi-objs-y += sbi_ipi.o
> libsbi-objs-y += sbi_irqchip.o
> +libsbi-objs-y += sbi_kasan.o
> +libsbi-objs-y += sbi_kasan_test.o
> libsbi-objs-y += sbi_platform.o
> libsbi-objs-y += sbi_pmu.o
> libsbi-objs-y += sbi_dbtr.o
> diff --git a/lib/sbi/sbi_domain.c b/lib/sbi/sbi_domain.c
> index 4f458ac0..0ad3d974 100644
> --- a/lib/sbi/sbi_domain.c
> +++ b/lib/sbi/sbi_domain.c
> @@ -18,6 +18,7 @@
> #include <sbi/sbi_platform.h>
> #include <sbi/sbi_scratch.h>
> #include <sbi/sbi_string.h>
> +#include <sbi/sbi_kasan.h>
>
> SBI_LIST_HEAD(domain_list);
>
> @@ -936,8 +937,21 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
> SBI_DOMAIN_MEMREGION_M_WRITABLE |
> SBI_DOMAIN_MEMREGION_FW),
> &root_memregs[root_memregs_count++]);
> +
> }
>
> + #ifdef KASAN_ENABLED
> + /*
> + * Protect KASAN Shadowmap memregion from lower privilege modes
> + */
> + sbi_domain_memregion_init(KASAN_SHADOW_MEMORY_START,
> + sbi_kasan_get_shadow_size(),
> + (SBI_DOMAIN_MEMREGION_M_READABLE |
> + SBI_DOMAIN_MEMREGION_M_WRITABLE |
> + SBI_DOMAIN_MEMREGION_FW),
> + &root_memregs[root_memregs_count++]);
> + #endif
> +
> root.fw_region_inited = true;
>
> /*
> @@ -967,7 +981,7 @@ int sbi_domain_init(struct sbi_scratch *scratch, u32 cold_hartid)
> /* Root domain possible and assigned HARTs */
> sbi_for_each_hartindex(i)
> sbi_hartmask_set_hartindex(i, root_hmask);
> -
> +
> /* Finally register the root domain */
> rc = sbi_domain_register(&root, root_hmask);
> if (rc)
> diff --git a/lib/sbi/sbi_heap.c b/lib/sbi/sbi_heap.c
> index 1de6dc1e..13500330 100644
> --- a/lib/sbi/sbi_heap.c
> +++ b/lib/sbi/sbi_heap.c
> @@ -39,6 +39,7 @@ struct sbi_heap_control {
>
> struct sbi_heap_control global_hpctrl;
>
> +__attribute__((no_sanitize("address")))
> static bool alloc_nodes(struct sbi_heap_control *hpctrl)
> {
> size_t size = HEAP_NODE_BATCH_SIZE * sizeof(struct heap_node);
> @@ -69,6 +70,7 @@ static bool alloc_nodes(struct sbi_heap_control *hpctrl)
> return true;
> }
>
> +__attribute__((no_sanitize("address")))
> static void *alloc_with_align(struct sbi_heap_control *hpctrl,
> size_t align, size_t size)
> {
> @@ -137,11 +139,13 @@ out:
> return ret;
> }
>
> +__attribute__((no_sanitize("address")))
> void *sbi_malloc_from(struct sbi_heap_control *hpctrl, size_t size)
> {
> return alloc_with_align(hpctrl, HEAP_ALLOC_ALIGN, size);
> }
>
> +__attribute__((no_sanitize("address")))
> void *sbi_aligned_alloc_from(struct sbi_heap_control *hpctrl,
> size_t alignment, size_t size)
> {
> @@ -159,15 +163,17 @@ void *sbi_aligned_alloc_from(struct sbi_heap_control *hpctrl,
> return alloc_with_align(hpctrl, alignment, size);
> }
>
> +__attribute__((no_sanitize("address")))
> void *sbi_zalloc_from(struct sbi_heap_control *hpctrl, size_t size)
> {
> - void *ret = sbi_malloc_from(hpctrl, size);
> + void *ret = zalloc_from(hpctrl, size); //function needed for KASAn integration
>
> if (ret)
> sbi_memset(ret, 0, size);
> return ret;
> }
>
> +__attribute__((no_sanitize("address")))
> void sbi_free_from(struct sbi_heap_control *hpctrl, void *ptr)
> {
> struct heap_node *n, *np;
> @@ -239,6 +245,7 @@ unsigned long sbi_heap_reserved_space_from(struct sbi_heap_control *hpctrl)
> return hpctrl->resv;
> }
>
> +__attribute__((no_sanitize("address")))
> int sbi_heap_init_new(struct sbi_heap_control *hpctrl, unsigned long base,
> unsigned long size)
> {
> diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
> index 5259064b..af33c266 100644
> --- a/lib/sbi/sbi_init.c
> +++ b/lib/sbi/sbi_init.c
> @@ -35,6 +35,8 @@
> #include <sbi/sbi_tlb.h>
> #include <sbi/sbi_version.h>
> #include <sbi/sbi_unit_test.h>
> +#include <sbi/sbi_kasan.h>
> +#include <sbi/sbi_kasan_test.h>
>
> #define BANNER \
> " ____ _____ ____ _____\n" \
> @@ -231,6 +233,10 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
> rc = sbi_scratch_init(scratch);
> if (rc)
> sbi_hart_hang();
> +
> + #ifdef KASAN_ENABLED
> + kasan_init(scratch);
> + #endif
>
> /* Note: This has to be second thing in coldboot init sequence */
> rc = sbi_heap_init(scratch);
> @@ -288,6 +294,14 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
>
> sbi_double_trap_init(scratch);
>
> + #ifdef KASAN_TESTS_ENABLED
> + heap_kasan_test();
> + stack_kasan_test();
> + globals_kasan_test();
> + memset_kasan_test();
> + memcpy_kasan_test();
> + #endif
> +
> rc = sbi_irqchip_init(scratch, true);
> if (rc) {
> sbi_printf("%s: irqchip init failed (error %d)\n",
> @@ -431,6 +445,10 @@ static void __noreturn init_warm_startup(struct sbi_scratch *scratch,
> rc = sbi_hart_init(scratch, false);
> if (rc)
> sbi_hart_hang();
> +
> + #ifdef KASAN_ENABLED
> + kasan_hart_init(scratch);
> + #endif
>
> rc = sbi_pmu_init(scratch, false);
> if (rc)
> diff --git a/lib/sbi/sbi_kasan.c b/lib/sbi/sbi_kasan.c
> new file mode 100644
> index 00000000..77e0dddf
> --- /dev/null
> +++ b/lib/sbi/sbi_kasan.c
> @@ -0,0 +1,514 @@
> +
> +/* SPDX-License-Identifier: BSD-2-Clause
> + * Copyright (c) 2018-2020 Maxime Villard, m00nbsd.net
> + *
> + * Author: Marcos Oduardo <marcos.oduardo at gmail.com>
> + *
> + * All rights reserved.
> + *
> + * This code is part of the KASAN subsystem of the NetBSD kernel.
> + *
> + * 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 AUTHOR ``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 AUTHOR 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 <sbi/sbi_kasan.h>
> +#include <sbi/sbi_console.h>
> +#include <sbi/sbi_heap.h>
> +#include <sbi/sbi_string.h>
> +#include <sbi/sbi_types.h>
> +#include <sbi/sbi_scratch.h>
> +
> +#ifdef KASAN_ENABLED
> +
> +#define __RET_ADDR ((unsigned long) __builtin_return_address(0))
> +
> +/* ASAN constants. Part of the compiler ABI. */
> +#define KASAN_SHADOW_SCALE_SHIFT 3
> +#define KASAN_SHADOW_SCALE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT)
> +#define KASAN_SHADOW_MASK (KASAN_SHADOW_SCALE_SIZE - 1)
> +
> +// Poison Values
> +#define KASAN_GENERIC_REDZONE 0xFA
> +#define KASAN_MALLOC_REDZONE 0xFB
> +#define KASAN_HEAP_FREE 0xFD
> +#define KASAN_STACK_LEFT 0xF1
> +#define KASAN_STACK_MID 0xF2
> +#define KASAN_STACK_RIGHT 0xF3
> +#define KASAN_SHADOW_RESERVED 0xFF
> +
> +#define KASAN_HEAD_SIZE 32
> +#define KASAN_TAIL_SIZE 32
> +
> +// BSD Macros
> +#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
> +#define __predict_true(x) __builtin_expect((x) != 0, 1)
> +#define __predict_false(x) __builtin_expect((x) != 0, 0)
> +
> +#define KASAN_MEM_TO_SHADOW(addr) \
> + (((addr) >> KASAN_SHADOW_SCALE_SHIFT) + __asan_shadow_memory_dynamic_address)
> +
> +static unsigned long kasan_enabled_offset;
> +static bool kasan_early_boot_done = false;
> +static unsigned long kasan_fw_base;
> +static unsigned long kasan_rw_offset;
> +static unsigned long kasan_fw_size;
> +unsigned long __asan_shadow_memory_dynamic_address; //shadow offset
> +static unsigned long kasan_shadow_size;
> +static unsigned long kasan_fw_start; //fw base + offset
> +static unsigned long kasan_fw_end; //fw base + size
> +
> +#define ADDR_CROSSES_SCALE_BOUNDARY(addr, size) \
> + ((addr >> KASAN_SHADOW_SCALE_SHIFT) != ((addr + size - 1) >> KASAN_SHADOW_SCALE_SHIFT))
> +
> +__attribute__((no_sanitize("address")))
> +static inline int8_t *kasan_md_addr_to_shad(const void *addr) {
> + return (int8_t *)(((unsigned long)(addr) >> KASAN_SHADOW_SCALE_SHIFT) + __asan_shadow_memory_dynamic_address);
> +}
> +
> +__attribute__((no_sanitize("address")))
> +static inline bool kasan_md_illegal(unsigned long addr, bool is_write) {
> + if (addr >= KASAN_SHADOW_MEMORY_START && addr < (KASAN_SHADOW_MEMORY_START + kasan_shadow_size))
> + return true;
> +
> + if (addr >= kasan_fw_base && addr < kasan_fw_start){
> + if (is_write) {
> + return true;
> + }
> + }
> +
> + return false;
> +
> +}
> +
> +__attribute__((no_sanitize("address")))
> +static inline bool kasan_md_unsupported(unsigned long addr) {
> + if (addr > kasan_fw_end) return true;
> +
> + if (addr < kasan_fw_base) return true;
> +
> + return false;
> +}
> +
> +__attribute__((no_sanitize("address")))
> +static inline const char *kasan_code_name(uint8_t code) {
> + switch (code) {
> + case KASAN_GENERIC_REDZONE: return "GenericRedZone";
> + case KASAN_MALLOC_REDZONE: return "MallocRedZone";
> + case KASAN_HEAP_FREE: return "UseAfterFree";
> + case 1 ... 7: return "RedZonePartial";
> + case KASAN_STACK_LEFT: return "StackLeft";
> + case KASAN_STACK_MID: return "StackMiddle";
> + case KASAN_STACK_RIGHT: return "StackRight";
> + default: return "Unknown";
> + }
> +}
> +
> +__attribute__((no_sanitize("address")))
> +static void kasan_report(unsigned long addr, size_t size, bool write, unsigned long pc, uint8_t code) {
> + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> + bool was_enabled = sbi_scratch_read_type(scratch, bool, kasan_enabled_offset);
> + sbi_scratch_write_type(scratch, bool, kasan_enabled_offset, false);
> +
> + sbi_printf("\n");
> + sbi_printf("ASan: Unauthorized Access In %p: Addr %p [%lu byte%s, %s, %s]\n",
> + (void *)pc, (void *)addr, (unsigned long)size, (size > 1 ? "s" : ""),
> + (write ? "write" : "read"), kasan_code_name(code));
> +
> + sbi_scratch_write_type(scratch, bool, kasan_enabled_offset, was_enabled);
> +}
> +
> +__attribute__((no_sanitize("address")))
> +static inline bool kasan_shadow_1byte_isvalid(unsigned long addr, uint8_t *code) {
> + int8_t *byte = kasan_md_addr_to_shad((void *)addr);
> + int8_t last = (int8_t)((addr & KASAN_SHADOW_MASK) + 1);
> +
> + if (__predict_true(*byte == 0 || last <= *byte)) {
> + return true;
> + }
> + *code = (uint8_t)*byte;
> + return false;
> +}
> +
> +__attribute__((no_sanitize("address")))
> +static inline bool kasan_shadow_2byte_isvalid(unsigned long addr, uint8_t *code) {
> + if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 2)) {
> + return (kasan_shadow_1byte_isvalid(addr, code) &&
> + kasan_shadow_1byte_isvalid(addr+1, code));
> + }
> + int8_t *byte = kasan_md_addr_to_shad((void *)addr);
> + int8_t last = (int8_t)(((addr + 1) & KASAN_SHADOW_MASK) + 1);
> +
> + if (__predict_true(*byte == 0 || last <= *byte)) {
> + return true;
> + }
> + *code = (uint8_t)*byte;
> + return false;
> +}
> +
> +__attribute__((no_sanitize("address")))
> +static inline bool kasan_shadow_4byte_isvalid(unsigned long addr, uint8_t *code) {
> + if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 4)) {
> + return (kasan_shadow_2byte_isvalid(addr, code) &&
> + kasan_shadow_2byte_isvalid(addr+2, code));
> + }
> + int8_t *byte = kasan_md_addr_to_shad((void *)addr);
> + int8_t last = (int8_t)(((addr + 3) & KASAN_SHADOW_MASK) + 1);
> +
> + if (__predict_true(*byte == 0 || last <= *byte)) {
> + return true;
> + }
> + *code = (uint8_t)*byte;
> + return false;
> +}
> +
> +__attribute__((no_sanitize("address")))
> +static inline bool kasan_shadow_8byte_isvalid(unsigned long addr, uint8_t *code) {
> + if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 8)) {
> + return (kasan_shadow_4byte_isvalid(addr, code) &&
> + kasan_shadow_4byte_isvalid(addr+4, code));
> + }
> + int8_t *byte = kasan_md_addr_to_shad((void *)addr);
> + int8_t last = (int8_t)(((addr + 7) & KASAN_SHADOW_MASK) + 1);
> +
> + if (__predict_true(*byte == 0 || last <= *byte)) {
> + return true;
> + }
> + *code = (uint8_t)*byte;
> + return false;
> +}
> +
> +__attribute__((no_sanitize("address")))
> +static inline bool kasan_shadow_Nbyte_isvalid(unsigned long addr, size_t size, uint8_t *code) {
> + size_t i;
> + for (i = 0; i < size; i++) {
> + if (!kasan_shadow_1byte_isvalid(addr+i, code)) return false;
> + }
> + return true;
> +}
> +
> +__attribute__((no_sanitize("address")))
> +void kasan_shadow_check(unsigned long addr, size_t size, bool write, unsigned long retaddr) {
> +
> + if (__predict_false(!kasan_early_boot_done)) return;
> +
> + uint8_t code = 0;
> + bool valid = true;
> + struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
> + bool enabled = sbi_scratch_read_type(scratch, bool, kasan_enabled_offset);
> + if (__predict_false(!enabled)) return;
> +
> + if (__predict_false(size == 0)) return;
> + if (__predict_false(kasan_md_illegal(addr, write))) {
> + kasan_report(addr, size, write, retaddr, KASAN_SHADOW_RESERVED);
> + return;
> + }
> + if (__predict_false(kasan_md_unsupported(addr))) return;
> +
> +
> +
> + if (__builtin_constant_p(size)) {
> + switch (size) {
> + case 1: valid = kasan_shadow_1byte_isvalid(addr, &code); break;
> + case 2: valid = kasan_shadow_2byte_isvalid(addr, &code); break;
> + case 4: valid = kasan_shadow_4byte_isvalid(addr, &code); break;
> + case 8: valid = kasan_shadow_8byte_isvalid(addr, &code); break;
> + default: valid = kasan_shadow_Nbyte_isvalid(addr, size, &code); break;
> + }
> + } else {
> + valid = kasan_shadow_Nbyte_isvalid(addr, size, &code);
> + }
> +
> + if (__predict_false(!valid)) {
> + kasan_report(addr, size, write, retaddr, code);
> + }
> +}
> +
> +__attribute__((no_sanitize("address")))
> +static void kasan_shadow_Nbyte_fill(const void *addr, size_t size, uint8_t code)
> +{
> + void *shad;
> +
> + if (__predict_false(size == 0)) return;
> + if (__predict_false(kasan_md_unsupported((unsigned long)addr))) return;
> +
> + shad = (void *)kasan_md_addr_to_shad(addr);
> + size = size >> KASAN_SHADOW_SCALE_SHIFT;
> +
> + _real_sbi_memset(shad, code, size);
> +}
> +
> +__attribute__((no_sanitize("address")))
> +static __always_inline void
> +kasan_shadow_1byte_markvalid(unsigned long addr)
> +{
> + int8_t *byte = kasan_md_addr_to_shad((void *)addr);
> + int8_t last = (addr & KASAN_SHADOW_MASK) + 1;
> +
> + *byte = last;
> +}
> +
> +__attribute__((no_sanitize("address")))
> +static __always_inline void
> +kasan_shadow_Nbyte_markvalid(const void *addr, size_t size)
> +{
> + size_t i;
> + for (i = 0; i < size; i++) {
> + kasan_shadow_1byte_markvalid((unsigned long)addr + i);
> + }
> +}
> +
> +/*
> + * In an area of size 'sz_with_redz', mark the 'size' first bytes as valid,
> + * and the rest as invalid. There are generally two use cases:
> + *
> + * o kasan_mark(addr, origsize, size, code), with origsize < size. This marks
> + * the redzone at the end of the buffer as invalid.
> + *
> + * o kasan_mark(addr, size, size, 0). This marks the entire buffer as valid.
> + */
> +
> + __attribute__((no_sanitize("address")))
> +void kasan_mark(const void *addr, size_t size, size_t sz_with_redz, uint8_t code)
> +{
> + size_t i, n, redz;
> + int8_t *shad;
> +
> + if (__predict_false(!kasan_early_boot_done)) return;
> + if (kasan_md_unsupported((unsigned long)addr)) return;
> +
> + redz = sz_with_redz - roundup(size, KASAN_SHADOW_SCALE_SIZE);
> + shad = kasan_md_addr_to_shad(addr);
> +
> + /* Chunks of 8 bytes, valid. */
> + n = size / KASAN_SHADOW_SCALE_SIZE;
> + for (i = 0; i < n; i++) {
> + *shad++ = 0;
> + }
> +
> + /* Possibly one chunk, mid. */
> + if ((size & KASAN_SHADOW_MASK) != 0) {
> + *shad++ = (size & KASAN_SHADOW_MASK);
> + }
> +
> + /* Chunks of 8 bytes, invalid. */
> + n = redz / KASAN_SHADOW_SCALE_SIZE;
> + for (i = 0; i < n; i++) {
> + *shad++ = code;
> + }
> +}
> +__attribute__((no_sanitize("address")))
> +void kasan_hart_init(struct sbi_scratch *scratch)
> +{
> + sbi_scratch_write_type(scratch, bool, kasan_enabled_offset, true);
> +}
> +
> +__attribute__((no_sanitize("address")))
> +void kasan_md_init(struct sbi_scratch *scratch)
> +{
> + kasan_fw_base = scratch->fw_start;
> + kasan_rw_offset = scratch->fw_rw_offset;
> + kasan_fw_size = scratch->fw_size;
> + kasan_fw_start = kasan_fw_base + kasan_rw_offset;
> + kasan_fw_end = kasan_fw_base + kasan_fw_size;
> + __asan_shadow_memory_dynamic_address = KASAN_SHADOW_MEMORY_START - (kasan_fw_start >> KASAN_SHADOW_SCALE_SHIFT);
> + kasan_shadow_size = (kasan_fw_end - kasan_fw_start + 1) >> KASAN_SHADOW_SCALE_SHIFT;
> +
> + _real_sbi_memset((void*)KASAN_SHADOW_MEMORY_START, 0, kasan_shadow_size);
> +
> + kasan_enabled_offset = sbi_scratch_alloc_offset(sizeof(bool));
> +}
> +
> +__attribute__((no_sanitize("address")))
> +void kasan_ctors(void)
> +{
> + extern unsigned long __CTOR_LIST__, __CTOR_END__;
> + size_t nentries, i;
> + unsigned long *ptr;
> +
> + nentries = ((size_t)&__CTOR_END__ - (size_t)&__CTOR_LIST__) / sizeof(unsigned long);
> +
> + ptr = &__CTOR_LIST__;
> + for (i = 0; i < nentries; i++) {
> + void (*func)(void);
> + func = (void *)(*ptr);
> + (*func)();
> + ptr++;
> + }
> +}
> +
> +
> +#define DEFINE_ASAN_LOAD_STORE(size) \
> + __attribute__((no_sanitize("address"))) void __asan_load##size(unsigned long addr) { \
> + kasan_shadow_check(addr, size, false, __RET_ADDR); \
> + } \
> + __attribute__((no_sanitize("address"))) void __asan_load##size##_noabort(unsigned long addr) { \
> + kasan_shadow_check(addr, size, false, __RET_ADDR); \
> + } \
> + __attribute__((no_sanitize("address"))) void __asan_store##size(unsigned long addr) { \
> + kasan_shadow_check(addr, size, true, __RET_ADDR); \
> + } \
> + __attribute__((no_sanitize("address"))) void __asan_store##size##_noabort(unsigned long addr) { \
> + kasan_shadow_check(addr, size, true, __RET_ADDR); \
> + }
> +
> +DEFINE_ASAN_LOAD_STORE(1)
> +DEFINE_ASAN_LOAD_STORE(2)
> +DEFINE_ASAN_LOAD_STORE(4)
> +DEFINE_ASAN_LOAD_STORE(8)
> +DEFINE_ASAN_LOAD_STORE(16)
> +
> +__attribute__((no_sanitize("address"))) void __asan_loadN(unsigned long addr, size_t size) {
> + kasan_shadow_check(addr, size, false, __RET_ADDR);
> +}
> +__attribute__((no_sanitize("address"))) void __asan_loadN_noabort(unsigned long addr, size_t size) {
> + kasan_shadow_check(addr, size, false, __RET_ADDR);
> +}
> +__attribute__((no_sanitize("address"))) void __asan_storeN(unsigned long addr, size_t size) {
> + kasan_shadow_check(addr, size, true, __RET_ADDR);
> +}
> +__attribute__((no_sanitize("address"))) void __asan_storeN_noabort(unsigned long addr, size_t size) {
> + kasan_shadow_check(addr, size, true, __RET_ADDR);
> +}
> +__attribute__((no_sanitize("address"))) void __asan_handle_no_return(void) {}
> +
> +struct __asan_global {
> + const void *beg;
> + size_t size;
> + size_t size_with_redzone;
> + const void *name;
> + const void *module_name;
> + unsigned long has_dynamic_init;
> + void *location;
> + unsigned long odr_indicator;
> +};
> +
> +__attribute__((no_sanitize("address")))
> +void __asan_register_globals(struct __asan_global *globals, size_t n) {
> + size_t i;
> + for (i = 0; i < n; i++) {
> + kasan_mark(globals[i].beg, globals[i].size,
> + globals[i].size_with_redzone, KASAN_GENERIC_REDZONE);
> + }
> +}
> +
> +__attribute__((no_sanitize("address")))
> +void __asan_unregister_globals(struct __asan_global *globals, size_t n) {
> +}
> +
> +
> +__attribute__((no_sanitize("address")))
> +void *kasan_malloc_hook(struct sbi_heap_control *hpctrl, size_t size) {
> + size_t aligned_size;
> + size_t total_size;
> + size_t *size_ptr;
> + void *ptr;
> + void *user_ptr;
> +
> + if (size == 0)
> + return NULL;
> +
> + aligned_size = roundup(size, KASAN_SHADOW_SCALE_SIZE);
> + total_size = sizeof(size_t) + KASAN_HEAD_SIZE + aligned_size + KASAN_TAIL_SIZE;
> +
> + ptr = sbi_malloc_from(hpctrl, total_size);
> + if (ptr == NULL)
> + return NULL;
> +
> + size_ptr = (size_t *)ptr;
> + *size_ptr = total_size;
> +
> + user_ptr = (uint8_t *)ptr + sizeof(size_t) + KASAN_HEAD_SIZE;
> +
> + kasan_shadow_Nbyte_fill(ptr, sizeof(size_t) + KASAN_HEAD_SIZE,
> + KASAN_MALLOC_REDZONE);
> +
> + kasan_mark(user_ptr, size, aligned_size + KASAN_TAIL_SIZE,
> + KASAN_MALLOC_REDZONE);
> +
> + return user_ptr;
> +}
> +
> +__attribute__((no_sanitize("address")))
> +void kasan_free_hook(struct sbi_heap_control *hpctrl, void *ptr) {
> + void *real_ptr;
> + size_t *size_ptr;
> + size_t total_size;
> + size_t poison_size;
> +
> + if (ptr == NULL)
> + return;
> +
> + real_ptr = (uint8_t *)ptr - (sizeof(size_t) + KASAN_HEAD_SIZE);
> +
> + size_ptr = (size_t *)real_ptr;
> + total_size = *size_ptr;
> +
> + sbi_free_from(hpctrl, real_ptr);
> +
> + poison_size = total_size - sizeof(size_t) - KASAN_HEAD_SIZE;
> + kasan_shadow_Nbyte_fill(ptr, poison_size, KASAN_HEAP_FREE);
> +}
> +
> +
> +#define DEFINE_ASAN_SET_SHADOW(byte) \
> + __attribute__((no_sanitize("address"))) \
> + void __asan_set_shadow_##byte(void *addr, size_t size) { \
> + _real_sbi_memset(addr, 0x##byte, size); \
> + }
> +
> +DEFINE_ASAN_SET_SHADOW(00)
> +DEFINE_ASAN_SET_SHADOW(f1)
> +DEFINE_ASAN_SET_SHADOW(f2)
> +DEFINE_ASAN_SET_SHADOW(f3)
> +
> +__attribute__((no_sanitize("address")))
> +void __asan_poison_stack_memory(const void *addr, size_t size) {
> + size = roundup(size, KASAN_SHADOW_SCALE_SIZE);
> + kasan_shadow_Nbyte_fill(addr, size, KASAN_STACK_MID);
> +}
> +
> +__attribute__((no_sanitize("address")))
> +void __asan_unpoison_stack_memory(const void *addr, size_t size) {
> + kasan_shadow_Nbyte_markvalid(addr, size);
> +}
> +
> +__attribute__((no_sanitize("address")))
> +void kasan_init(struct sbi_scratch *scratch) {
> + kasan_md_init(scratch);
> + kasan_early_boot_done = true;
> + kasan_ctors();
> + kasan_hart_init(scratch);
> +}
> +
> +__attribute__((no_sanitize("address")))
> +void sbi_kasan_get_shadow_region(struct sbi_domain_memregion *reg)
> +{
> + sbi_domain_memregion_init(KASAN_SHADOW_MEMORY_START, kasan_shadow_size, 0, reg);
> +}
> +
> +__attribute__((no_sanitize("address")))
> +unsigned long sbi_kasan_get_shadow_size(void)
> +{
> + return kasan_shadow_size;
> +}
> +
> +#endif
> diff --git a/lib/sbi/sbi_kasan_test.c b/lib/sbi/sbi_kasan_test.c
> new file mode 100644
> index 00000000..d5ecb93a
> --- /dev/null
> +++ b/lib/sbi/sbi_kasan_test.c
> @@ -0,0 +1,66 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + * Author: Marcos Oduardo <marcos.oduardo at gmail.com>
> + */
> +
> +#ifdef KASAN_TESTS_ENABLED
> +#include <sbi/sbi_kasan_test.h>
> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic ignored "-Warray-bounds"
> +
> +int global_int_arr[17];
> +
> +void globals_kasan_test(void) {
> + int overflow_idx = 18;
> + sbi_printf("\n*** KASAn global overflow test ***\n");
> + sbi_printf("Global array: %lu elements (int), base address: %p\n",
> + sizeof(global_int_arr) / sizeof(int), (void*)&global_int_arr);
> + sbi_printf("Writing integer to index %d (overflow)\n", overflow_idx);
> + global_int_arr[overflow_idx] = 0;
> +}
> +
> +void heap_kasan_test(void) {
> + int bad_idx = 18;
> + int alloc_sz = 17;
> + unsigned char *mem_ptr = sbi_malloc(alloc_sz);
> + sbi_printf("\n*** KASAn heap overflow test ***\n");
> + sbi_printf("Allocated buffer: %d bytes at address %p\n", alloc_sz, mem_ptr);
> + sbi_printf("Writing to index %d (overflow by %d bytes)\n", bad_idx, bad_idx - alloc_sz + 1);
> + mem_ptr[bad_idx] = 0;
> +}
> +
> +char stack_read_result;
> +
> +void stack_kasan_test(void) {
> + char local_buf[17];
> + int invalid_idx = 17;
> + sbi_printf("\n*** KASAn stack overflow test ***\n");
> + sbi_printf("Stack buffer size: %lu bytes, location: %p\n",
> + sizeof(local_buf), (void*)&local_buf);
> + sbi_printf("Reading from index %d (overflow by %d bytes)\n",
> + invalid_idx, invalid_idx - (int)sizeof(local_buf) + 1);
> + stack_read_result = local_buf[invalid_idx];
> +}
> +
> +char global_byte_buf[17];
> +
> +void memset_kasan_test(void) {
> + int write_sz = 18;
> + sbi_printf("\n*** KASAn memset overflow test ***\n");
> + sbi_printf("Target buffer: %lu bytes at %p\n",
> + sizeof(global_byte_buf), (void*)&global_byte_buf);
> + sbi_printf("Memset size: %d bytes with pattern 0xaa (overflow by 1)\n", write_sz);
> + sbi_memset(global_byte_buf, 0xaa, write_sz);
> +}
> +
> +void memcpy_kasan_test(void) {
> + char dest_buf[18];
> + int copy_sz = sizeof(dest_buf);
> + sbi_printf("\n*** KASAN memcpy overflow test ***\n");
> + sbi_printf("Source: %lu bytes (global_byte_buf)\n", sizeof(global_byte_buf));
> + sbi_printf("Copying %d bytes to local buffer (read overflow by 1)\n", copy_sz);
> + sbi_memcpy(dest_buf, global_byte_buf, copy_sz);
> +}
> +
> +#pragma GCC diagnostic pop
> +#endif
> \ No newline at end of file
> diff --git a/lib/sbi/sbi_string.c b/lib/sbi/sbi_string.c
> index f4f13942..89be9fca 100644
> --- a/lib/sbi/sbi_string.c
> +++ b/lib/sbi/sbi_string.c
> @@ -13,179 +13,275 @@
> */
>
> #include <sbi/sbi_string.h>
> +#include <sbi/sbi_kasan.h>
>
> +#define __RET_ADDR ((unsigned long) __builtin_return_address(0))
> /*
> Provides sbi_strcmp for the completeness of supporting string functions.
> it is not recommended to use sbi_strcmp() but use sbi_strncmp instead.
> */
> int sbi_strcmp(const char *a, const char *b)
> {
> - /* search first diff or end of string */
> - for (; *a == *b && *a != '\0'; a++, b++)
> - ;
> + /* search first diff or end of string */
> + for (; *a == *b && *a != '\0'; a++, b++)
> + ;
>
> - return *a - *b;
> + return *a - *b;
> }
>
> int sbi_strncmp(const char *a, const char *b, size_t count)
> {
> - /* search first diff or end of string */
> - for (; count > 0 && *a == *b && *a != '\0'; a++, b++, count--)
> - ;
> + /* search first diff or end of string */
> + for (; count > 0 && *a == *b && *a != '\0'; a++, b++, count--)
> + ;
>
> - /* No difference till the end */
> - if (!count)
> - return 0;
> + /* No difference till the end */
> + if (!count)
> + return 0;
>
> - return *a - *b;
> + return *a - *b;
> }
>
> size_t sbi_strlen(const char *str)
> {
> - unsigned long ret = 0;
> + unsigned long ret = 0;
>
> - while (*str != '\0') {
> - ret++;
> - str++;
> - }
> + while (*str != '\0') {
> + ret++;
> + str++;
> + }
>
> - return ret;
> + return ret;
> }
>
> size_t sbi_strnlen(const char *str, size_t count)
> {
> - unsigned long ret = 0;
> + unsigned long ret = 0;
>
> - while (*str != '\0' && ret < count) {
> - ret++;
> - str++;
> - }
> + while (*str != '\0' && ret < count) {
> + ret++;
> + str++;
> + }
>
> - return ret;
> + return ret;
> }
>
> char *sbi_strcpy(char *dest, const char *src)
> {
> - char *ret = dest;
> + char *ret = dest;
>
> - while ((*dest++ = *src++) != '\0') {
> - }
> - return ret;
> + while ((*dest++ = *src++) != '\0') {
> + }
> + return ret;
> }
>
> char *sbi_strncpy(char *dest, const char *src, size_t count)
> {
> - char *tmp = dest;
> -
> - while (count) {
> - if ((*tmp = *src) != 0)
> - src++;
> - tmp++;
> - count--;
> - }
> - return dest;
> + char *tmp = dest;
> +
> + while (count) {
> + if ((*tmp = *src) != 0)
> + src++;
> + tmp++;
> + count--;
> + }
> + return dest;
> }
>
> char *sbi_strchr(const char *s, int c)
> {
> - while (*s != '\0' && *s != (char)c)
> - s++;
> + while (*s != '\0' && *s != (char)c)
> + s++;
>
> - if (*s == '\0')
> - return NULL;
> - else
> - return (char *)s;
> + if (*s == '\0')
> + return NULL;
> + else
> + return (char *)s;
> }
>
> char *sbi_strrchr(const char *s, int c)
> {
> - const char *last = s + sbi_strlen(s);
> + const char *last = s + sbi_strlen(s);
>
> - while (last > s && *last != (char)c)
> - last--;
> + while (last > s && *last != (char)c)
> + last--;
>
> - if (*last != (char)c)
> - return NULL;
> - else
> - return (char *)last;
> + if (*last != (char)c)
> + return NULL;
> + else
> + return (char *)last;
> }
> -void *sbi_memset(void *s, int c, size_t count)
> -{
> - char *temp = s;
> +#ifdef KASAN_ENABLED
> +__attribute__((no_sanitize("address")))
> +void *_real_sbi_memset(void *s, int c, size_t count){
> +
> + char *temp = s;
> +
> + while (count > 0) {
> + count--;
> + *temp++ = c;
> + }
>
> - while (count > 0) {
> - count--;
> - *temp++ = c;
> - }
> + return s;
>
> - return s;
> }
> +__attribute__((no_sanitize("address")))
> +void *_real_sbi_memcpy(void *dest, const void *src, size_t count){
> +
> + char *temp1 = dest;
> + const char *temp2 = src;
>
> -void *sbi_memcpy(void *dest, const void *src, size_t count)
> -{
> - char *temp1 = dest;
> - const char *temp2 = src;
> + while (count > 0) {
> + *temp1++ = *temp2++;
> + count--;
> + }
>
> - while (count > 0) {
> - *temp1++ = *temp2++;
> - count--;
> - }
> + return dest;
>
> - return dest;
> }
>
> -void *sbi_memmove(void *dest, const void *src, size_t count)
> +__attribute__((no_sanitize("address")))
> +void *_real_sbi_memmove(void *dest, const void *src, size_t count)
> {
> - char *temp1 = (char *)dest;
> - const char *temp2 = (char *)src;
> -
> - if (src == dest)
> - return dest;
> -
> - if (dest < src) {
> - while (count > 0) {
> - *temp1++ = *temp2++;
> - count--;
> - }
> - } else {
> - temp1 = (char *)dest + count - 1;
> - temp2 = (char *)src + count - 1;
> + char *temp1 = (char *)dest;
> + const char *temp2 = (char *)src;
> +
> + if (src == dest)
> + return dest;
> +
> + if (dest < src) {
> + while (count > 0) {
> + *temp1++ = *temp2++;
> + count--;
> + }
> + } else {
> + temp1 = (char *)dest + count - 1;
> + temp2 = (char *)src + count - 1;
> +
> + while (count > 0) {
> + *temp1-- = *temp2--;
> + count--;
> + }
> + }
> +
> + return dest;
> +}
> +#endif
> +
> +__attribute__((no_sanitize("address")))
> +void *sbi_memset(void *s, int c, unsigned long count) {
> + #ifdef KASAN_ENABLED
> + kasan_shadow_check((unsigned long)s, count, true, __RET_ADDR);
> + return _real_sbi_memset(s, c, count);
> + #endif
> +
> + char *temp = s;
> +
> + while (count > 0) {
> + count--;
> + *temp++ = c;
> + }
> +
> + return s;
> +}
>
> - while (count > 0) {
> - *temp1-- = *temp2--;
> - count--;
> - }
> - }
> +__attribute__((no_sanitize("address")))
> +void *sbi_memcpy(void *dest, const void *src, unsigned long count) {
> + #ifdef KASAN_ENABLED
> + kasan_shadow_check((unsigned long)src, count, false, __RET_ADDR);
> + kasan_shadow_check((unsigned long)dest, count, true, __RET_ADDR);
> + return _real_sbi_memcpy(dest, src, count);
> +
> + #endif
> +
> + char *temp1 = dest;
> + const char *temp2 = src;
> +
> + while (count > 0) {
> + *temp1++ = *temp2++;
> + count--;
> + }
> +
> + return dest;
> +}
>
> - return dest;
> +__attribute__((no_sanitize("address")))
> +void *sbi_memmove(void *dest, const void *src, size_t count)
> +{
> + #ifdef KASAN_ENABLED
> + kasan_shadow_check((unsigned long)src, count, false, __RET_ADDR);
> + kasan_shadow_check((unsigned long)dest, count, true, __RET_ADDR);
> + return _real_sbi_memmove(dest, src, count);
> + #endif
> +
> + char *temp1 = (char *)dest;
> + const char *temp2 = (char *)src;
> +
> + if (src == dest)
> + return dest;
> +
> + if (dest < src) {
> + while (count > 0) {
> + *temp1++ = *temp2++;
> + count--;
> + }
> + } else {
> + temp1 = (char *)dest + count - 1;
> + temp2 = (char *)src + count - 1;
> +
> + while (count > 0) {
> + *temp1-- = *temp2--;
> + count--;
> + }
> + }
> +
> + return dest;
> }
>
> int sbi_memcmp(const void *s1, const void *s2, size_t count)
> {
> - const char *temp1 = s1;
> - const char *temp2 = s2;
> -
> - for (; count > 0 && (*temp1 == *temp2); count--) {
> - temp1++;
> - temp2++;
> - }
> -
> - if (count > 0)
> - return *(unsigned char *)temp1 - *(unsigned char *)temp2;
> - else
> - return 0;
> + const char *temp1 = s1;
> + const char *temp2 = s2;
> +
> + for (; count > 0 && (*temp1 == *temp2); count--) {
> + temp1++;
> + temp2++;
> + }
> +
> + if (count > 0)
> + return *(unsigned char *)temp1 - *(unsigned char *)temp2;
> + else
> + return 0;
> }
>
> void *sbi_memchr(const void *s, int c, size_t count)
> {
> - const unsigned char *temp = s;
> + const unsigned char *temp = s;
>
> - while (count > 0) {
> - if ((unsigned char)c == *temp++) {
> - return (void *)(temp - 1);
> - }
> - count--;
> - }
> + while (count > 0) {
> + if ((unsigned char)c == *temp++) {
> + return (void *)(temp - 1);
> + }
> + count--;
> + }
>
> - return NULL;
> + return NULL;
> +}
> +
> +__attribute__((no_sanitize("address")))
> +void *memset(void *s, int c, size_t count)
> +{
> + return sbi_memset(s, c, count);
> }
> +
> +__attribute__((no_sanitize("address")))
> +void *memcpy(void *dest, const void *src, size_t count)
> +{
> + return sbi_memcpy(dest, src, count);
> +}
> +
> +__attribute__((no_sanitize("address")))
> +void *memmove(void *dest, const void *src, size_t count)
> +{
> + return sbi_memmove(dest, src, count);
> +}
> \ No newline at end of file
> diff --git a/platform/generic/objects.mk b/platform/generic/objects.mk
> index c4a8fee2..f1b696f4 100644
> --- a/platform/generic/objects.mk
> +++ b/platform/generic/objects.mk
> @@ -37,7 +37,6 @@ ifeq ($(PLATFORM_RISCV_XLEN), 32)
> # This needs to be 4MB aligned for 32-bit system
> FW_PAYLOAD_OFFSET=0x400000
> else
> - # This needs to be 2MB aligned for 64-bit system
> - FW_PAYLOAD_OFFSET=0x200000
> + FW_PAYLOAD_OFFSET=0x200000 # This needs to be 2MB aligned for 64-bit system
> endif
> FW_PAYLOAD_FDT_OFFSET=$(FW_JUMP_FDT_OFFSET)
> --
> 2.52.0
>
More information about the opensbi
mailing list