From 87dc91b58865031941e96a99c859d40052a1f221 Mon Sep 17 00:00:00 2001 From: yinshengkai Date: Tue, 20 Aug 2024 10:41:56 +0800 Subject: [PATCH] mm/kasan: add kasan watch point implementation Signed-off-by: yinshengkai --- include/nuttx/mm/kasan.h | 24 ++++++++ mm/Kconfig | 11 ++++ mm/kasan/hook.c | 124 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+) diff --git a/include/nuttx/mm/kasan.h b/include/nuttx/mm/kasan.h index 8db1a23928..aeeb8f3f5c 100644 --- a/include/nuttx/mm/kasan.h +++ b/include/nuttx/mm/kasan.h @@ -30,6 +30,8 @@ #include #include +#include + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -193,6 +195,28 @@ void kasan_start(void); void kasan_stop(void); +/**************************************************************************** + * Name: kasan_debugpoint + * + * Description: + * Monitor the memory range for invalid access check + * + * Input Parameters: + * type - DEBUGPOINT_NONE : remove + * DEBUGPOINT_WATCHPOINT_RO: read + * DEBUGPOINT_WATCHPOINT_WO: write + * DEBUGPOINT_WATCHPOINT_RW: read/write + * addr - range start address + * size - range size + * + * Returned Value: + * If the setting is successful, it returns 0, otherwise it + * returns an error code. + * + ****************************************************************************/ + +int kasan_debugpoint(int type, FAR void *addr, size_t size); + #undef EXTERN #ifdef __cplusplus } diff --git a/mm/Kconfig b/mm/Kconfig index d6c00e5fe5..fa74e0c098 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -264,6 +264,11 @@ choice prompt "KAsan Mode" default MM_KASAN_GENERIC +config MM_KASAN_NONE + bool "KAsan disable" + ---help--- + Disable KASan check + config MM_KASAN_GENERIC bool "KAsan generic mode" ---help--- @@ -288,6 +293,12 @@ config MM_KASAN_ALL to check. Enabling this option will get image size increased and performance decreased significantly. +config MM_KASAN_WATCHPOINT + int "Kasan watchpoint maximum number" + default 0 + ---help--- + The maximum number of watchpoints that can be set by KASan. + config MM_KASAN_DISABLE_NULL_POINTER_CHECK bool "Disable null pointer access check" default n diff --git a/mm/kasan/hook.c b/mm/kasan/hook.c index da2bd65bca..56f06f523e 100644 --- a/mm/kasan/hook.c +++ b/mm/kasan/hook.c @@ -83,12 +83,33 @@ # define MM_KASAN_DISABLE_WRITE_PANIC 0 #endif +#ifdef CONFIG_MM_KASAN_WATCHPOINT +# define MM_KASAN_WATCHPOINT CONFIG_MM_KASAN_WATCHPOINT +#else +# define MM_KASAN_WATCHPOINT 0 +#endif + #define KASAN_INIT_VALUE 0xdeadcafe +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct kasan_watchpoint_s +{ + FAR void *addr; + size_t size; + int type; +}; + /**************************************************************************** * Private Data ****************************************************************************/ +#if MM_KASAN_WATCHPOINT > 0 +static struct kasan_watchpoint_s g_watchpoint[MM_KASAN_WATCHPOINT]; +#endif + static uint32_t g_region_init; /**************************************************************************** @@ -164,6 +185,37 @@ static void kasan_report(FAR const void *addr, size_t size, leave_critical_section(flags); } +#if MM_KASAN_WATCHPOINT > 0 +static void kasan_check_watchpoint(FAR const void *addr, size_t size, + bool is_write, + FAR void *return_address) +{ + int i; + + for (i = 0; i < MM_KASAN_WATCHPOINT; i++) + { + FAR struct kasan_watchpoint_s *watchpoint = &g_watchpoint[i]; + + if (watchpoint->type == DEBUGPOINT_NONE) + { + break; + } + + if (addr + size <= watchpoint->addr || + addr > watchpoint->addr + watchpoint->size) + { + continue; + } + + if ((is_write && (watchpoint->type & DEBUGPOINT_WATCHPOINT_WO)) || + (!is_write && (watchpoint->type & DEBUGPOINT_WATCHPOINT_RO))) + { + kasan_report(addr, size, is_write, return_address); + } + } +} +#endif + static inline void kasan_check_report(FAR const void *addr, size_t size, bool is_write, FAR void *return_address) @@ -180,10 +232,16 @@ static inline void kasan_check_report(FAR const void *addr, size_t size, } #endif +#ifndef CONFIG_MM_KASAN_NONE if (kasan_is_poisoned(addr, size)) { kasan_report(addr, size, is_write, return_address); } +#endif + +#if MM_KASAN_WATCHPOINT > 0 + kasan_check_watchpoint(addr, size, is_write, return_address); +#endif } /**************************************************************************** @@ -200,6 +258,72 @@ void kasan_stop(void) g_region_init = 0; } +/**************************************************************************** + * Name: kasan_debugpoint + * + * Description: + * Monitor the memory range for invalid access check + * + * Input Parameters: + * type - DEBUGPOINT_NONE : remove + * DEBUGPOINT_WATCHPOINT_RO: read + * DEBUGPOINT_WATCHPOINT_WO: write + * DEBUGPOINT_WATCHPOINT_RW: read/write + * addr - range start address + * size - range size + * + * Returned Value: + * If the setting is successful, it returns 0, otherwise it + * returns an error code. + * + ****************************************************************************/ + +#if MM_KASAN_WATCHPOINT > 0 +int kasan_debugpoint(int type, FAR void *addr, size_t size) +{ + FAR struct kasan_watchpoint_s *watchpoint; + int i; + int j; + + if (addr == NULL || size == 0) + { + return -EINVAL; + } + + for (i = 0; i < MM_KASAN_WATCHPOINT; i++) + { + watchpoint = &g_watchpoint[i]; + if (watchpoint->type == DEBUGPOINT_NONE || watchpoint->addr == addr) + { + if (type != DEBUGPOINT_NONE) + { + watchpoint->addr = addr; + watchpoint->size = size; + watchpoint->type = type; + return 0; + } + + for (j = MM_KASAN_WATCHPOINT - 1; j > i; j--) + { + if (g_watchpoint[j].type != DEBUGPOINT_NONE) + { + watchpoint->addr = g_watchpoint[j].addr; + watchpoint->size = g_watchpoint[j].size; + watchpoint->type = g_watchpoint[j].type; + watchpoint = &g_watchpoint[j]; + break; + } + } + + watchpoint->type = DEBUGPOINT_NONE; + return 0; + } + } + + return -ENOMEM; +} +#endif + void __asan_before_dynamic_init(FAR const void *module_name) { /* Shut up compiler complaints */