From 85ad50c39e0b67bf6529ec85387553961815423b Mon Sep 17 00:00:00 2001 From: yinshengkai Date: Mon, 22 Apr 2024 18:44:20 +0800 Subject: [PATCH] testing: refactor kasan test Signed-off-by: yinshengkai --- testing/kasantest/kasantest.c | 312 ++++++++++++++++++++++------------ 1 file changed, 205 insertions(+), 107 deletions(-) diff --git a/testing/kasantest/kasantest.c b/testing/kasantest/kasantest.c index e3d4a6a28..171773337 100644 --- a/testing/kasantest/kasantest.c +++ b/testing/kasantest/kasantest.c @@ -22,154 +22,252 @@ * Included Files ****************************************************************************/ -#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include #include -#include -#include -#include - /**************************************************************************** - * Pre-processor Definitions + * Private Types Prototypes ****************************************************************************/ -#define KASAN_TEST_MEM_SIZE 128 +typedef struct testcase_s +{ + bool (*func)(FAR struct mm_heap_s *heap, size_t size); + FAR const char *name; +} testcase_t; + +typedef struct run_s +{ + char argv[16]; + FAR const testcase_t *testcase; + FAR struct mm_heap_s *heap; + size_t size; +} run_t; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static bool test_heap_underflow(FAR struct mm_heap_s *heap, size_t size); +static bool test_heap_overflow(FAR struct mm_heap_s *heap, size_t size); +static bool test_heap_use_after_free(FAR struct mm_heap_s *heap, + size_t size); +static bool test_heap_invalid_free(FAR struct mm_heap_s *heap, size_t size); +static bool test_heap_double_free(FAR struct mm_heap_s *heap, size_t size); +static bool test_heap_poison(FAR struct mm_heap_s *heap, size_t size); +static bool test_heap_unpoison(FAR struct mm_heap_s *heap, size_t size); +static bool test_heap_memset(FAR struct mm_heap_s *heap, size_t size); +static bool test_heap_memcpy(FAR struct mm_heap_s *heap, size_t size); +static bool test_heap_memmove(FAR struct mm_heap_s *heap, size_t size); /**************************************************************************** * Private Data ****************************************************************************/ -static char g_kasan_test_buffer[KASAN_TEST_MEM_SIZE]; +const static testcase_t g_kasan_test[] = +{ + {test_heap_underflow, "heap underflow"}, + {test_heap_overflow, "heap overflow"}, + {test_heap_use_after_free, "heap use after free"}, + {test_heap_invalid_free, "heap inval free"}, + {test_heap_double_free, "test heap double free"}, + {test_heap_poison, "heap poison"}, + {test_heap_unpoison, "heap unpoison"}, + {test_heap_memset, "heap memset"}, + {test_heap_memcpy, "heap memcpy"}, + {test_heap_memmove, "heap memmove"} +}; /**************************************************************************** * Private Functions ****************************************************************************/ -static void kasan_test(char *p, size_t size) +static bool test_heap_underflow(FAR struct mm_heap_s *heap, size_t size) { - size_t i; - - for (i = 0; i < size + 64; i++) - { - syslog(LOG_SYSLOG, - "Access Buffer[%zu] : %zu address: %p", size, i, &p[i]); - p[i]++; - syslog(LOG_SYSLOG, "read: %02x -- Successful\n", p[i]); - } + FAR uint8_t *mem = mm_malloc(heap, size); + *(mem - 1) = 0x12; + return false; } -static void kasan_test_use_after_free(void) +static bool test_heap_overflow(FAR struct mm_heap_s *heap, size_t size) { - char *ptr = malloc(KASAN_TEST_MEM_SIZE); + FAR uint8_t *mem = mm_malloc(heap, size); + size = mm_malloc_size(heap, mem); - if (ptr == NULL) + mem[size + 1] = 0x11; + return false; +} + +static bool test_heap_use_after_free(FAR struct mm_heap_s *heap, size_t size) +{ + FAR uint8_t *mem = mm_malloc(heap, size); + + mm_free(heap, mem); + mem[0] = 0x10; + return 0; +} + +static bool test_heap_invalid_free(FAR struct mm_heap_s *heap, size_t size) +{ + int x; + mm_free(heap, &x); + return false; +} + +static bool test_heap_double_free(FAR struct mm_heap_s *heap, size_t size) +{ + uint8_t *mem = mm_malloc(heap, size); + + mm_free(heap, mem); + mm_free(heap, mem); + return false; +} + +static bool test_heap_poison(FAR struct mm_heap_s *heap, size_t size) +{ + FAR uint8_t *mem = mm_malloc(heap, size); + size = mm_malloc_size(heap, mem); + + kasan_poison(mem, size); + mem[0] = 0x10; + return false; +} + +static bool test_heap_unpoison(FAR struct mm_heap_s *heap, size_t size) +{ + FAR uint8_t *mem = mm_malloc(heap, size); + size_t memsize = mm_malloc_size(heap, mem); + + kasan_poison(mem, memsize); + kasan_unpoison(mem, memsize); + mem[0] = 0x10; + return true; +} + +static bool test_heap_memset(FAR struct mm_heap_s *heap, size_t size) +{ + FAR uint8_t *mem = mm_malloc(heap, size); + size = mm_malloc_size(heap, mem); + + memset(mem, 0x11, size + 1); + return false; +} + +static bool test_heap_memcpy(FAR struct mm_heap_s *heap, size_t size) +{ + FAR uint8_t *src; + FAR uint8_t *dst; + + size = size / 2; + src = mm_malloc(heap, size); + size = mm_malloc_size(heap, src); + dst = mm_malloc(heap, size); + + memcpy(dst, src, size); + memcpy(dst, src, size + 4); + return false; +} + +static bool test_heap_memmove(FAR struct mm_heap_s *heap, size_t size) +{ + FAR uint8_t *src; + FAR uint8_t *dst; + + size = size / 2; + src = mm_malloc(heap, size); + size = mm_malloc_size(heap, src); + dst = mm_malloc(heap, size); + + memmove(dst, src, size); + memmove(dst, src, size + 4); + return false; +} + +static int run_testcase(int argc, FAR char *argv[]) +{ + FAR run_t *run = (FAR run_t *)(uintptr_t)strtoul(argv[1], NULL, 0); + return run->testcase->func(run->heap, run->size); +} + +static int run_test(FAR const testcase_t *test) +{ + size_t heap_size = 65536; + FAR char *argv[3]; + FAR run_t *run; + int status; + pid_t pid; + + /* There is a memory leak here because we cannot guarantee that + * it can be released correctly. + */ + + run = malloc(sizeof(run_t) + heap_size); + if (!run) { - syslog(LOG_SYSLOG, "Failed to allocate memory\n"); - return; + return ERROR; } - syslog(LOG_SYSLOG, "KASan test use after free\n"); - strcpy(ptr, "kasan test use after free"); - free(ptr); - printf("%s\n", ptr); -} - -static void kasan_test_heap_memory_out_of_bounds(char *str) -{ - char *endptr; - size_t size; - char *ptr; - - size = strtoul(str, &endptr, 0); - if (*endptr != '\0') + snprintf(run->argv, sizeof(run->argv), "%p", run); + run->testcase = test; + run->size = rand() % (heap_size / 2) + 1; + run->heap = mm_initialize("kasan", &run[1], heap_size); + if (!run->heap) { - printf("Conversion failed: Not a valid integer.\n"); - return; + free(run); + return ERROR; } - ptr = zalloc(size); - if (ptr == NULL) + argv[0] = "kasantest"; + argv[1] = run->argv; + argv[2] = NULL; + + posix_spawn(&pid, "kasantest", NULL, NULL, argv, NULL); + waitpid(pid, &status, 0); + if (status == 0) { - syslog(LOG_SYSLOG, "Failed to allocate memory\n"); - return; + printf("KASan test: %s, size: %d FAIL\n", test->name, run->size); + } + else + { + printf("KASan test: %s, size: %d PASS\n", test->name, run->size); } - syslog(LOG_SYSLOG, - "KASan test accessing heap memory out of bounds completed\n"); - kasan_test(ptr, size); -} - -static void kasan_test_global_variable_out_of_bounds(void) -{ - syslog(LOG_SYSLOG, - "KASan test accessing global variable out of bounds\n"); - kasan_test(g_kasan_test_buffer, KASAN_TEST_MEM_SIZE); -} - -static void *mm_stampede_thread(void *arg) -{ - char *p = (char *)arg; - - syslog(LOG_SYSLOG, "Child thread is running"); - kasan_test(p, KASAN_TEST_MEM_SIZE); - pthread_exit(NULL); -} - -static void kasan_test_memory_stampede(void) -{ - pthread_t thread; - char array[KASAN_TEST_MEM_SIZE]; - - syslog(LOG_SYSLOG, "KASan test accessing memory stampede\n"); - pthread_create(&thread, NULL, mm_stampede_thread, kasan_reset_tag(&array)); - pthread_join(thread, NULL); + return 0; } /**************************************************************************** * Public Functions ****************************************************************************/ -/**************************************************************************** - * Name: kasantest_main - ****************************************************************************/ - -int main(int argc, char *argv[]) +int main(int argc, FAR char *argv[]) { - /* NutttX cannot check the secondary release - * because the mm module has closed kasan instrumentation - */ - if (argc < 2) { - printf("Usage: %s \n", argv[0]); - printf("Available test options:\n"); - printf(" -u : Test use after free\n"); - printf(" -h : Test heap memory out of bounds (provide size)\n"); - printf(" -g : Test global variable out of bounds\n"); - printf(" -s : Test memory stampede\n"); - return 0; - } - else if (strncmp(argv[1], "-u", 2) == 0) - { - kasan_test_use_after_free(); - } - else if (strncmp(argv[1], "-h", 2) == 0 && argc == 3) - { - kasan_test_heap_memory_out_of_bounds(argv[2]); - } - else if (strncmp(argv[1], "-g", 2) == 0) - { - kasan_test_global_variable_out_of_bounds(); - } - else if (strncmp(argv[1], "-s", 2) == 0) - { - kasan_test_memory_stampede(); + size_t j; + for (j = 0; j < nitems(g_kasan_test); j++) + { + if (run_test(&g_kasan_test[j]) < 0) + { + return EXIT_FAILURE; + } + } } else { - printf("Unknown test option: %s\n", argv[1]); + return run_testcase(argc, argv); } - syslog(LOG_SYSLOG, "KASan test failed, please check\n"); - return 0; + return EXIT_SUCCESS; }