You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2024/09/13 15:14:14 UTC
(nuttx-apps) 01/05: testing: refactor kasan test
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
commit 85ad50c39e0b67bf6529ec85387553961815423b
Author: yinshengkai <yi...@xiaomi.com>
AuthorDate: Mon Apr 22 18:44:20 2024 +0800
testing: refactor kasan test
Signed-off-by: yinshengkai <yi...@xiaomi.com>
---
testing/kasantest/kasantest.c | 276 ++++++++++++++++++++++++++++--------------
1 file changed, 187 insertions(+), 89 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 <nuttx/config.h>
-#include <nuttx/mm/kasan.h>
-
+#include <assert.h>
+#include <malloc.h>
+#include <pthread.h>
+#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
#include <syslog.h>
-#include <pthread.h>
+
+#include <sys/param.h>
+#include <sys/wait.h>
+
+#include <nuttx/fs/procfs.h>
+#include <nuttx/mm/mm.h>
+#include <nuttx/mm/kasan.h>
+
+/****************************************************************************
+ * Private Types Prototypes
+ ****************************************************************************/
+
+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;
/****************************************************************************
- * Pre-processor Definitions
+ * Private Function Prototypes
****************************************************************************/
-#define KASAN_TEST_MEM_SIZE 128
+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;
+ FAR uint8_t *mem = mm_malloc(heap, size);
+ *(mem - 1) = 0x12;
+ return false;
+}
- 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]);
- }
+static bool test_heap_overflow(FAR struct mm_heap_s *heap, size_t size)
+{
+ FAR uint8_t *mem = mm_malloc(heap, size);
+ size = mm_malloc_size(heap, mem);
+
+ mem[size + 1] = 0x11;
+ return false;
}
-static void kasan_test_use_after_free(void)
+static bool test_heap_use_after_free(FAR struct mm_heap_s *heap, size_t size)
{
- char *ptr = malloc(KASAN_TEST_MEM_SIZE);
+ FAR uint8_t *mem = mm_malloc(heap, size);
- if (ptr == NULL)
- {
- syslog(LOG_SYSLOG, "Failed to allocate memory\n");
- return;
- }
+ mm_free(heap, mem);
+ mem[0] = 0x10;
+ return 0;
+}
- syslog(LOG_SYSLOG, "KASan test use after free\n");
- strcpy(ptr, "kasan test use after free");
- free(ptr);
- printf("%s\n", ptr);
+static bool test_heap_invalid_free(FAR struct mm_heap_s *heap, size_t size)
+{
+ int x;
+ mm_free(heap, &x);
+ return false;
}
-static void kasan_test_heap_memory_out_of_bounds(char *str)
+static bool test_heap_double_free(FAR struct mm_heap_s *heap, size_t size)
{
- char *endptr;
- size_t size;
- char *ptr;
+ uint8_t *mem = mm_malloc(heap, size);
- size = strtoul(str, &endptr, 0);
- if (*endptr != '\0')
- {
- printf("Conversion failed: Not a valid integer.\n");
- return;
- }
+ mm_free(heap, mem);
+ mm_free(heap, mem);
+ return false;
+}
- ptr = zalloc(size);
- if (ptr == NULL)
- {
- syslog(LOG_SYSLOG, "Failed to allocate memory\n");
- return;
- }
+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);
- syslog(LOG_SYSLOG,
- "KASan test accessing heap memory out of bounds completed\n");
- kasan_test(ptr, size);
+ kasan_poison(mem, size);
+ mem[0] = 0x10;
+ return false;
}
-static void kasan_test_global_variable_out_of_bounds(void)
+static bool test_heap_unpoison(FAR struct mm_heap_s *heap, size_t size)
{
- syslog(LOG_SYSLOG,
- "KASan test accessing global variable out of bounds\n");
- kasan_test(g_kasan_test_buffer, KASAN_TEST_MEM_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 void *mm_stampede_thread(void *arg)
+static bool test_heap_memset(FAR struct mm_heap_s *heap, size_t size)
{
- char *p = (char *)arg;
+ FAR uint8_t *mem = mm_malloc(heap, size);
+ size = mm_malloc_size(heap, mem);
- syslog(LOG_SYSLOG, "Child thread is running");
- kasan_test(p, KASAN_TEST_MEM_SIZE);
- pthread_exit(NULL);
+ memset(mem, 0x11, size + 1);
+ return false;
}
-static void kasan_test_memory_stampede(void)
+static bool test_heap_memcpy(FAR struct mm_heap_s *heap, size_t size)
{
- pthread_t thread;
- char array[KASAN_TEST_MEM_SIZE];
+ FAR uint8_t *src;
+ FAR uint8_t *dst;
- syslog(LOG_SYSLOG, "KASan test accessing memory stampede\n");
- pthread_create(&thread, NULL, mm_stampede_thread, kasan_reset_tag(&array));
- pthread_join(thread, NULL);
+ 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;
}
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
+static bool test_heap_memmove(FAR struct mm_heap_s *heap, size_t size)
+{
+ FAR uint8_t *src;
+ FAR uint8_t *dst;
-/****************************************************************************
- * Name: kasantest_main
- ****************************************************************************/
+ 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);
+}
-int main(int argc, char *argv[])
+static int run_test(FAR const testcase_t *test)
{
- /* NutttX cannot check the secondary release
- * because the mm module has closed kasan instrumentation
+ 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.
*/
- if (argc < 2)
+ run = malloc(sizeof(run_t) + heap_size);
+ if (!run)
{
- printf("Usage: %s <test_option>\n", argv[0]);
- printf("Available test options:\n");
- printf(" -u : Test use after free\n");
- printf(" -h <arg> : 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;
+ return ERROR;
}
- else if (strncmp(argv[1], "-u", 2) == 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)
{
- kasan_test_use_after_free();
+ free(run);
+ return ERROR;
}
- else if (strncmp(argv[1], "-h", 2) == 0 && argc == 3)
+
+ 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)
{
- kasan_test_heap_memory_out_of_bounds(argv[2]);
+ printf("KASan test: %s, size: %d FAIL\n", test->name, run->size);
}
- else if (strncmp(argv[1], "-g", 2) == 0)
+ else
{
- kasan_test_global_variable_out_of_bounds();
+ printf("KASan test: %s, size: %d PASS\n", test->name, run->size);
}
- else if (strncmp(argv[1], "-s", 2) == 0)
+
+ return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+ if (argc < 2)
{
- 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;
}