diff --git a/Documentation/guides/kasan.rst b/Documentation/guides/kasan.rst index ba669ee3b0..9a40346bb8 100644 --- a/Documentation/guides/kasan.rst +++ b/Documentation/guides/kasan.rst @@ -143,4 +143,3 @@ If you want the module you are writing to not be inserted by the compiler, you can add the option 'CFLAGS += -fno-sanitize=kernel-address' to a single module. If it is a file, you can write it this way, special_file.o: CFLAGS = -fno-sanitize=kernel-address -or : special_file.o: CFLAGS = -fno-sanitize=kernel-hwaddress diff --git a/arch/arm64/src/Toolchain.defs b/arch/arm64/src/Toolchain.defs index a8485ad697..162d4fd411 100644 --- a/arch/arm64/src/Toolchain.defs +++ b/arch/arm64/src/Toolchain.defs @@ -79,11 +79,7 @@ ifeq ($(CONFIG_MM_UBSAN_TRAP_ON_ERROR),y) endif ifeq ($(CONFIG_MM_KASAN_ALL),y) - ifeq ($(CONFIG_MM_KASAN_GENERIC),y) - ARCHOPTIMIZATION += -fsanitize=kernel-address - else ifeq ($(CONFIG_MM_KASAN_SW_TAGS),y) - ARCHOPTIMIZATION += -fsanitize=kernel-hwaddress - endif + ARCHOPTIMIZATION += -fsanitize=kernel-address endif ifeq ($(CONFIG_MM_KASAN_GLOBAL),y) diff --git a/mm/Kconfig b/mm/Kconfig index 39b8901185..8841969199 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -328,7 +328,7 @@ config MM_KASAN_DISABLE_WRITES_CHECK config MM_KASAN_GLOBAL bool "Enable global data check" - depends on MM_KASAN_GENERIC + depends on MM_KASAN_ALL default n ---help--- This option enables KASan global data check. diff --git a/mm/kasan/CMakeLists.txt b/mm/kasan/CMakeLists.txt index c904b5c03a..44f924a10a 100644 --- a/mm/kasan/CMakeLists.txt +++ b/mm/kasan/CMakeLists.txt @@ -23,13 +23,7 @@ set(SRCS hook.c) if(CONFIG_MM_KASAN) list(APPEND FLAGS -fno-builtin) - if(CONFIG_MM_KASAN_GENERIC) - list(APPEND FLAGS -fno-sanitize=kernel-address) - endif() - - if(CONFIG_MM_KASAN_SW_TAGS) - list(APPEND FLAGS -fno-sanitize=kernel-hwaddress) - endif() + list(APPEND FLAGS -fno-sanitize=kernel-address) if(CONFIG_LTO_NONE) list(APPEND FLAGS -fno-lto) diff --git a/mm/kasan/Make.defs b/mm/kasan/Make.defs index 94ab9a0e18..025867350b 100644 --- a/mm/kasan/Make.defs +++ b/mm/kasan/Make.defs @@ -23,23 +23,14 @@ CSRCS += hook.c ifeq ($(CONFIG_MM_KASAN),y) - - ifeq ($(CONFIG_MM_KASAN_GENERIC),y) - CFLAGS += -fno-sanitize=kernel-address - endif - - ifeq ($(CONFIG_MM_KASAN_SW_TAGS),y) - CFLAGS += -fno-sanitize=kernel-hwaddress - endif + CFLAGS += -fno-builtin + CFLAGS += -fno-sanitize=kernel-address ifeq ($(CONFIG_LTO_NONE),n) CFLAGS += -fno-lto endif - endif -CFLAGS += -fno-builtin - # Add the core heap directory to the build DEPPATH += --dep-path kasan diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c index 2a13364f32..b5b6d3ee56 100644 --- a/mm/kasan/generic.c +++ b/mm/kasan/generic.c @@ -51,10 +51,6 @@ #define KASAN_REGION_SIZE(size) \ (sizeof(struct kasan_region_s) + KASAN_SHADOW_SIZE(size)) -#ifdef CONFIG_MM_KASAN_GLOBAL -# define KASAN_GLOBAL_SHADOW_SCALE (32) -#endif - /**************************************************************************** * Private Types ****************************************************************************/ @@ -74,21 +70,13 @@ static FAR struct kasan_region_s *g_region[CONFIG_MM_KASAN_REGIONS]; static size_t g_region_count; static spinlock_t g_lock; -/**************************************************************************** - * Public Data - ****************************************************************************/ - -#ifdef CONFIG_MM_KASAN_GLOBAL -extern const struct kasan_region_s *g_global_region[]; -#endif - /**************************************************************************** * Private Functions ****************************************************************************/ static inline_function FAR uintptr_t * kasan_mem_to_shadow(FAR const void *ptr, size_t size, - FAR unsigned int *bit, FAR size_t *align) + FAR unsigned int *bit) { uintptr_t addr = (uintptr_t)ptr; size_t i; @@ -99,30 +87,12 @@ kasan_mem_to_shadow(FAR const void *ptr, size_t size, { DEBUGASSERT(addr + size <= g_region[i]->end); addr -= g_region[i]->begin; - *align = KASAN_SHADOW_SCALE; addr /= KASAN_SHADOW_SCALE; *bit = addr % KASAN_BITS_PER_WORD; return &g_region[i]->shadow[addr / KASAN_BITS_PER_WORD]; } } -#ifdef CONFIG_MM_KASAN_GLOBAL - for (i = 0; g_global_region[i]; i++) - { - if (addr >= g_global_region[i]->begin - && addr < g_global_region[i]->end) - { - DEBUGASSERT(addr + size <= g_global_region[i]->end); - addr -= g_global_region[i]->begin; - *align = KASAN_GLOBAL_SHADOW_SCALE; - addr /= KASAN_GLOBAL_SHADOW_SCALE; - *bit = addr % KASAN_BITS_PER_WORD; - return (FAR uintptr_t *) - &g_global_region[i]->shadow[addr / KASAN_BITS_PER_WORD]; - } - } -#endif - return NULL; } @@ -133,23 +103,22 @@ kasan_is_poisoned(FAR const void *addr, size_t size) unsigned int bit; unsigned int nbit; uintptr_t mask; - size_t align; - p = kasan_mem_to_shadow(addr, size, &bit, &align); + p = kasan_mem_to_shadow(addr, size, &bit); if (p == NULL) { - return false; + return kasan_global_is_poisoned(addr, size); } - if (size <= align) + if (size <= KASAN_SHADOW_SCALE) { return ((*p >> bit) & 1); } nbit = KASAN_BITS_PER_WORD - bit % KASAN_BITS_PER_WORD; mask = KASAN_FIRST_WORD_MASK(bit); - size = ALIGN_UP(size, align); - size /= align; + size = ALIGN_UP(size, KASAN_SHADOW_SCALE); + size /= KASAN_SHADOW_SCALE; while (size >= nbit) { @@ -185,9 +154,8 @@ static void kasan_set_poison(FAR const void *addr, size_t size, unsigned int bit; unsigned int nbit; uintptr_t mask; - size_t align; - p = kasan_mem_to_shadow(addr, size, &bit, &align); + p = kasan_mem_to_shadow(addr, size, &bit); if (p == NULL) { return; @@ -195,7 +163,7 @@ static void kasan_set_poison(FAR const void *addr, size_t size, nbit = KASAN_BITS_PER_WORD - bit % KASAN_BITS_PER_WORD; mask = KASAN_FIRST_WORD_MASK(bit); - size /= align; + size /= KASAN_SHADOW_SCALE; flags = spin_lock_irqsave(&g_lock); while (size >= nbit) diff --git a/mm/kasan/global.c b/mm/kasan/global.c new file mode 100644 index 0000000000..19645ebdee --- /dev/null +++ b/mm/kasan/global.c @@ -0,0 +1,138 @@ +/**************************************************************************** + * mm/kasan/global.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define KASAN_BYTES_PER_WORD (sizeof(uintptr_t)) +#define KASAN_BITS_PER_WORD (KASAN_BYTES_PER_WORD * 8) + +#define KASAN_GLOBAL_FIRST_WORD_MASK(start) \ + (UINTPTR_MAX << ((start) & (KASAN_BITS_PER_WORD - 1))) +#define KASAN_GLOBAL_LAST_WORD_MASK(end) \ + (UINTPTR_MAX >> (-(end) & (KASAN_BITS_PER_WORD - 1))) + +#define KASAN_GLOBAL_SHADOW_SCALE (32) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct kasan_global_region_s +{ + uintptr_t begin; + uintptr_t end; + uintptr_t shadow[1]; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +extern const struct kasan_global_region_s *g_global_region[]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline_function FAR uintptr_t * +kasan_global_mem_to_shadow(FAR const void *ptr, size_t size, + FAR unsigned int *bit) +{ + uintptr_t addr = (uintptr_t)ptr; + size_t i; + + for (i = 0; g_global_region[i]; i++) + { + if (addr >= g_global_region[i]->begin && + addr < g_global_region[i]->end) + { + DEBUGASSERT(addr + size <= g_global_region[i]->end); + addr -= g_global_region[i]->begin; + addr /= KASAN_GLOBAL_SHADOW_SCALE; + *bit = addr % KASAN_BITS_PER_WORD; + return (FAR uintptr_t *) + &g_global_region[i]->shadow[addr / KASAN_BITS_PER_WORD]; + } + } + + return NULL; +} + +static inline_function bool +kasan_global_is_poisoned(FAR const void *addr, size_t size) +{ + FAR uintptr_t *p; + unsigned int bit; + unsigned int nbit; + uintptr_t mask; + + p = kasan_global_mem_to_shadow(addr, size, &bit); + if (p == NULL) + { + return false; + } + + if (size <= KASAN_GLOBAL_SHADOW_SCALE) + { + return ((*p >> bit) & 1); + } + + nbit = KASAN_BITS_PER_WORD - bit % KASAN_BITS_PER_WORD; + mask = KASAN_GLOBAL_FIRST_WORD_MASK(bit); + size = ALIGN_UP(size, KASAN_GLOBAL_SHADOW_SCALE); + size /= KASAN_GLOBAL_SHADOW_SCALE; + + while (size >= nbit) + { + if ((*p++ & mask) != 0) + { + return true; + } + + bit += nbit; + size -= nbit; + + nbit = KASAN_BITS_PER_WORD; + mask = UINTPTR_MAX; + } + + if (size) + { + mask &= KASAN_GLOBAL_LAST_WORD_MASK(bit + size); + if ((*p & mask) != 0) + { + return true; + } + } + + return false; +} diff --git a/mm/kasan/hook.c b/mm/kasan/hook.c index 694767af21..9289473590 100644 --- a/mm/kasan/hook.c +++ b/mm/kasan/hook.c @@ -32,6 +32,12 @@ #include #include +#ifdef CONFIG_MM_KASAN_GLOBAL +# include "global.c" +#else +# define kasan_global_is_poisoned(addr, size) false +#endif + #ifdef CONFIG_MM_KASAN_GENERIC # include "generic.c" #elif defined(CONFIG_MM_KASAN_SW_TAGS) @@ -70,16 +76,6 @@ kasan_check_report(addr, size, true, return_address(0)); \ } -#define DEFINE_HWASAN_LOAD_STORE(size) \ - void __hwasan_load##size##_noabort(void *addr) \ - { \ - kasan_check_report(addr, size, false, return_address(0)); \ - } \ - void __hwasan_store##size##_noabort(void *addr) \ - { \ - kasan_check_report(addr, size, true, return_address(0)); \ - } - #ifdef CONFIG_MM_KASAN_DISABLE_READ_PANIC # define MM_KASAN_DISABLE_READ_PANIC 1 #else @@ -403,21 +399,3 @@ DEFINE_ASAN_LOAD_STORE(2) DEFINE_ASAN_LOAD_STORE(4) DEFINE_ASAN_LOAD_STORE(8) DEFINE_ASAN_LOAD_STORE(16) - -/* Soft tags KASan will instrument the following functions */ - -void __hwasan_loadN_noabort(FAR void *addr, size_t size) -{ - kasan_check_report(addr, size, false, return_address(0)); -} - -void __hwasan_storeN_noabort(FAR void *addr, size_t size) -{ - kasan_check_report(addr, size, true, return_address(0)); -} - -DEFINE_HWASAN_LOAD_STORE(1) -DEFINE_HWASAN_LOAD_STORE(2) -DEFINE_HWASAN_LOAD_STORE(4) -DEFINE_HWASAN_LOAD_STORE(8) -DEFINE_HWASAN_LOAD_STORE(16) diff --git a/mm/kasan/sw_tags.c b/mm/kasan/sw_tags.c index c9592f17c3..58eae8d0da 100644 --- a/mm/kasan/sw_tags.c +++ b/mm/kasan/sw_tags.c @@ -106,7 +106,7 @@ kasan_is_poisoned(FAR const void *addr, size_t size) p = kasan_mem_to_shadow(addr, size); if (p == NULL) { - return false; + return kasan_global_is_poisoned(addr, size); } size = KASAN_SHADOW_SIZE(size);