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;
 }