From 071af0c9930eabd87bd4d179ed77d4dc1d600c94 Mon Sep 17 00:00:00 2001 From: wangmingrong1 Date: Wed, 18 Sep 2024 15:51:02 +0800 Subject: [PATCH] mm/kasan: Tag kasan and generic kasan use the same instrumentation options 1. Tested on QEMU, the two sockets were basically the same, and their performance was not affected. The size of the generated bin file was also the same 2. Extract global detection as a separate file, both types of Kasan support global variable out of bounds detection simultaneously Signed-off-by: wangmingrong1 --- Documentation/guides/kasan.rst | 1 - arch/arm64/src/Toolchain.defs | 6 +- mm/Kconfig | 2 +- mm/kasan/CMakeLists.txt | 8 +- mm/kasan/Make.defs | 13 +--- mm/kasan/generic.c | 48 ++---------- mm/kasan/global.c | 138 +++++++++++++++++++++++++++++++++ mm/kasan/hook.c | 34 ++------ mm/kasan/sw_tags.c | 2 +- 9 files changed, 158 insertions(+), 94 deletions(-) create mode 100644 mm/kasan/global.c 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);