mm/kasan: add kasan watch point implementation

Signed-off-by: yinshengkai <yinshengkai@xiaomi.com>
This commit is contained in:
yinshengkai 2024-08-20 10:41:56 +08:00 committed by Xiang Xiao
parent e154c6d071
commit 87dc91b588
3 changed files with 159 additions and 0 deletions

View File

@ -30,6 +30,8 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <nuttx/arch.h>
/**************************************************************************** /****************************************************************************
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
@ -193,6 +195,28 @@ void kasan_start(void);
void kasan_stop(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 #undef EXTERN
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -264,6 +264,11 @@ choice
prompt "KAsan Mode" prompt "KAsan Mode"
default MM_KASAN_GENERIC default MM_KASAN_GENERIC
config MM_KASAN_NONE
bool "KAsan disable"
---help---
Disable KASan check
config MM_KASAN_GENERIC config MM_KASAN_GENERIC
bool "KAsan generic mode" bool "KAsan generic mode"
---help--- ---help---
@ -288,6 +293,12 @@ config MM_KASAN_ALL
to check. Enabling this option will get image size increased to check. Enabling this option will get image size increased
and performance decreased significantly. 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 config MM_KASAN_DISABLE_NULL_POINTER_CHECK
bool "Disable null pointer access check" bool "Disable null pointer access check"
default n default n

View File

@ -83,12 +83,33 @@
# define MM_KASAN_DISABLE_WRITE_PANIC 0 # define MM_KASAN_DISABLE_WRITE_PANIC 0
#endif #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 #define KASAN_INIT_VALUE 0xdeadcafe
/****************************************************************************
* Private Types
****************************************************************************/
struct kasan_watchpoint_s
{
FAR void *addr;
size_t size;
int type;
};
/**************************************************************************** /****************************************************************************
* Private Data * Private Data
****************************************************************************/ ****************************************************************************/
#if MM_KASAN_WATCHPOINT > 0
static struct kasan_watchpoint_s g_watchpoint[MM_KASAN_WATCHPOINT];
#endif
static uint32_t g_region_init; 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); 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, static inline void kasan_check_report(FAR const void *addr, size_t size,
bool is_write, bool is_write,
FAR void *return_address) FAR void *return_address)
@ -180,10 +232,16 @@ static inline void kasan_check_report(FAR const void *addr, size_t size,
} }
#endif #endif
#ifndef CONFIG_MM_KASAN_NONE
if (kasan_is_poisoned(addr, size)) if (kasan_is_poisoned(addr, size))
{ {
kasan_report(addr, size, is_write, return_address); 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; 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) void __asan_before_dynamic_init(FAR const void *module_name)
{ {
/* Shut up compiler complaints */ /* Shut up compiler complaints */