You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gu...@apache.org on 2021/11/02 16:32:57 UTC

[incubator-nuttx] 02/03: mm: Support the kernel address sanitizer

This is an automated email from the ASF dual-hosted git repository.

gustavonihei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 39cdd99d77137e1c92859cf8dd7a2675690cc1d6
Author: chenwei23 <ch...@xiaomi.com>
AuthorDate: Sat Oct 9 15:22:28 2021 +0800

    mm: Support the kernel address sanitizer
    
    Signed-off-by: chenwei23 <ch...@xiaomi.com>
---
 mm/Kconfig                   |   8 +
 mm/Makefile                  |   1 +
 mm/kasan/Make.defs           |  34 ++++
 mm/kasan/kasan.c             | 409 +++++++++++++++++++++++++++++++++++++++++++
 mm/kasan/kasan.h             | 115 ++++++++++++
 mm/mm_heap/mm_free.c         |   5 +
 mm/mm_heap/mm_initialize.c   |   5 +
 mm/mm_heap/mm_malloc.c       |  20 +--
 mm/mm_heap/mm_memalign.c     |   7 +
 mm/mm_heap/mm_realloc.c      |  19 +-
 mm/umm_heap/umm_initialize.c |  13 +-
 tools/nxstyle.c              |   9 +
 12 files changed, 625 insertions(+), 20 deletions(-)

diff --git a/mm/Kconfig b/mm/Kconfig
index 8c5e772..8746a20 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -178,4 +178,12 @@ config MM_CIRCBUF
 	---help---
 		Build in support for the circular buffer management.
 
+config MM_KASAN
+	bool "Kernel Address Sanitizer"
+	default n
+	---help---
+		KASan is a fast compiler-based tool for detecting memory
+		bugs in native code. After turn on this option, Please
+		add -fsanitize=kernel-address to CFLAGS/CXXFLAGS too.
+
 source "mm/iob/Kconfig"
diff --git a/mm/Makefile b/mm/Makefile
index 0398029..323a8ed 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -29,6 +29,7 @@ include mm_gran/Make.defs
 include shm/Make.defs
 include iob/Make.defs
 include circbuf/Make.defs
+include kasan/Make.defs
 
 BINDIR ?= bin
 
diff --git a/mm/kasan/Make.defs b/mm/kasan/Make.defs
new file mode 100644
index 0000000..ab67a9c
--- /dev/null
+++ b/mm/kasan/Make.defs
@@ -0,0 +1,34 @@
+############################################################################
+# mm/kasan/Make.defs
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+ifeq ($(CONFIG_MM_KASAN),y)
+
+CSRCS += kasan.c
+
+# Disable kernel-address in mm subsystem
+
+CFLAGS += -fno-sanitize=kernel-address
+
+# Add the core heap directory to the build
+
+DEPPATH += --dep-path kasan
+VPATH += :kasan
+
+endif
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c
new file mode 100644
index 0000000..90c324e
--- /dev/null
+++ b/mm/kasan/kasan.c
@@ -0,0 +1,409 @@
+/****************************************************************************
+ * mm/kasan/kasan.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/semaphore.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "kasan.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define KASAN_BYTES_PER_WORD (sizeof(uintptr_t))
+#define KASAN_BITS_PER_WORD  (KASAN_BYTES_PER_WORD * 8)
+
+#define KASAN_FIRST_WORD_MASK(start) \
+  (UINTPTR_MAX << ((start) & (KASAN_BITS_PER_WORD - 1)))
+#define KASAN_LAST_WORD_MASK(end) \
+  (UINTPTR_MAX >> (-(end) & (KASAN_BITS_PER_WORD - 1)))
+
+#define KASAN_SHADOW_SCALE (sizeof(uintptr_t))
+
+#define KASAN_SHADOW_SIZE(size) \
+  (KASAN_BYTES_PER_WORD * ((size) / KASAN_SHADOW_SCALE / KASAN_BITS_PER_WORD))
+#define KASAN_REGION_SIZE(size) \
+  (sizeof(struct kasan_region_s) + KASAN_SHADOW_SIZE(size))
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct kasan_region_s
+{
+  FAR struct kasan_region_s *next;
+  uintptr_t                  begin;
+  uintptr_t                  end;
+  uintptr_t                  shadow[1];
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static sem_t g_lock = SEM_INITIALIZER(1);
+static FAR struct kasan_region_s *g_region;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static FAR uintptr_t *kasan_mem_to_shadow(uintptr_t addr, size_t size,
+                                          unsigned int *bit)
+{
+  FAR struct kasan_region_s *region;
+
+  for (region = g_region; region != NULL; region = region->next)
+    {
+      if (addr >= region->begin && addr < region->end)
+        {
+          DEBUGASSERT(addr + size <= region->end);
+          addr -= region->begin;
+          addr /= KASAN_SHADOW_SCALE;
+          *bit  = addr % KASAN_BITS_PER_WORD;
+          return &region->shadow[addr / KASAN_BITS_PER_WORD];
+        }
+    }
+
+  return NULL;
+}
+
+static void kasan_report(uintptr_t addr, size_t size, bool is_write)
+{
+  static int recursion;
+
+  if (++recursion == 1)
+    {
+      _alert("kasan detected a %s access error, address at %0#"PRIxPTR
+            ", size is %zu\n", is_write ? "write" : "read", addr, size);
+      PANIC();
+    }
+
+  --recursion;
+}
+
+static bool kasan_is_poisoned(uintptr_t addr, size_t size)
+{
+  FAR uintptr_t *p;
+  unsigned int bit;
+
+  p = kasan_mem_to_shadow(addr + size - 1, 1, &bit);
+  return p && ((*p >> bit) & 1);
+}
+
+static void kasan_set_poison(uintptr_t addr, size_t size, bool poisoned)
+{
+  FAR uintptr_t *p;
+  unsigned int bit;
+  unsigned int nbit;
+  uintptr_t mask;
+
+  p = kasan_mem_to_shadow(addr, size, &bit);
+  DEBUGASSERT(p != NULL);
+
+  nbit = KASAN_BITS_PER_WORD - bit % KASAN_BITS_PER_WORD;
+  mask = KASAN_FIRST_WORD_MASK(bit);
+
+  size /= KASAN_SHADOW_SCALE;
+  while (size >= nbit)
+    {
+      if (poisoned)
+        {
+          *p++ |= mask;
+        }
+      else
+        {
+          *p++ &= ~mask;
+        }
+
+      bit  += nbit;
+      size -= nbit;
+
+      nbit = KASAN_BITS_PER_WORD;
+      mask = UINTPTR_MAX;
+    }
+
+  if (size)
+    {
+      mask &= KASAN_LAST_WORD_MASK(bit + size);
+      if (poisoned)
+        {
+          *p |= mask;
+        }
+      else
+        {
+          *p &= ~mask;
+        }
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/* Exported functions called from other mm module */
+
+void kasan_poison(FAR const void *addr, size_t size)
+{
+  kasan_set_poison((uintptr_t)addr, size, true);
+}
+
+void kasan_unpoison(FAR const void *addr, size_t size)
+{
+  kasan_set_poison((uintptr_t)addr, size, false);
+}
+
+void kasan_register(FAR void *addr, FAR size_t *size)
+{
+  FAR struct kasan_region_s *region;
+
+  region = (FAR struct kasan_region_s *)
+    ((FAR char *)addr + *size - KASAN_REGION_SIZE(*size));
+
+  region->begin = (uintptr_t)addr;
+  region->end   = region->begin + *size;
+
+  _SEM_WAIT(&g_lock);
+  region->next = g_region;
+  g_region     = region;
+  _SEM_POST(&g_lock);
+
+  kasan_poison(addr, *size);
+  *size -= KASAN_REGION_SIZE(*size);
+}
+
+/* Exported functions called from the compiler generated code */
+
+void __sanitizer_annotate_contiguous_container(FAR const void *beg,
+                                               FAR const void *end,
+                                               FAR const void *old_mid,
+                                               FAR const void *new_mid)
+{
+  /* Shut up compiler complaints */
+}
+
+void __asan_before_dynamic_init(FAR const char *module_name)
+{
+  /* Shut up compiler complaints */
+}
+
+void __asan_after_dynamic_init(void)
+{
+  /* Shut up compiler complaints */
+}
+
+void __asan_handle_no_return(void)
+{
+  /* Shut up compiler complaints */
+}
+
+void __asan_report_load_n_noabort(uintptr_t addr, size_t size)
+{
+  kasan_report(addr, size, false);
+}
+
+void __asan_report_store_n_noabort(uintptr_t addr, size_t size)
+{
+  kasan_report(addr, size, true);
+}
+
+void __asan_report_load16_noabort(uintptr_t addr)
+{
+  __asan_report_load_n_noabort(addr, 16);
+}
+
+void __asan_report_store16_noabort(uintptr_t addr)
+{
+  __asan_report_store_n_noabort(addr, 16);
+}
+
+void __asan_report_load8_noabort(uintptr_t addr)
+{
+  __asan_report_load_n_noabort(addr, 8);
+}
+
+void __asan_report_store8_noabort(uintptr_t addr)
+{
+  __asan_report_store_n_noabort(addr, 8);
+}
+
+void __asan_report_load4_noabort(uintptr_t addr)
+{
+  __asan_report_load_n_noabort(addr, 4);
+}
+
+void __asan_report_store4_noabort(uintptr_t addr)
+{
+  __asan_report_store_n_noabort(addr, 4);
+}
+
+void __asan_report_load2_noabort(uintptr_t addr)
+{
+  __asan_report_load_n_noabort(addr, 2);
+}
+
+void __asan_report_store2_noabort(uintptr_t addr)
+{
+  __asan_report_store_n_noabort(addr, 2);
+}
+
+void __asan_report_load1_noabort(uintptr_t addr)
+{
+  __asan_report_load_n_noabort(addr, 1);
+}
+
+void __asan_report_store1_noabort(uintptr_t addr)
+{
+  __asan_report_store_n_noabort(addr, 1);
+}
+
+void __asan_loadN_noabort(uintptr_t addr, size_t size)
+{
+  if (kasan_is_poisoned(addr, size))
+    {
+      kasan_report(addr, size, false);
+    }
+}
+
+void __asan_storeN_noabort(uintptr_t addr, size_t size)
+{
+  if (kasan_is_poisoned(addr, size))
+    {
+      kasan_report(addr, size, true);
+    }
+}
+
+void __asan_load16_noabort(uintptr_t addr)
+{
+  __asan_loadN_noabort(addr, 16);
+}
+
+void __asan_store16_noabort(uintptr_t addr)
+{
+  __asan_storeN_noabort(addr, 16);
+}
+
+void __asan_load8_noabort(uintptr_t addr)
+{
+  __asan_loadN_noabort(addr, 8);
+}
+
+void __asan_store8_noabort(uintptr_t addr)
+{
+  __asan_storeN_noabort(addr, 8);
+}
+
+void __asan_load4_noabort(uintptr_t addr)
+{
+  __asan_loadN_noabort(addr, 4);
+}
+
+void __asan_store4_noabort(uintptr_t addr)
+{
+  __asan_storeN_noabort(addr, 4);
+}
+
+void __asan_load2_noabort(uintptr_t addr)
+{
+  __asan_loadN_noabort(addr, 2);
+}
+
+void __asan_store2_noabort(uintptr_t addr)
+{
+  __asan_storeN_noabort(addr, 2);
+}
+
+void __asan_load1_noabort(uintptr_t addr)
+{
+  __asan_loadN_noabort(addr, 1);
+}
+
+void __asan_store1_noabort(uintptr_t addr)
+{
+  __asan_storeN_noabort(addr, 1);
+}
+
+void __asan_loadN(uintptr_t addr, size_t size)
+{
+  __asan_loadN_noabort(addr, size);
+}
+
+void __asan_storeN(uintptr_t addr, size_t size)
+{
+  __asan_storeN_noabort(addr, size);
+}
+
+void __asan_load16(uintptr_t addr)
+{
+  __asan_load16_noabort(addr);
+}
+
+void __asan_store16(uintptr_t addr)
+{
+  __asan_store16_noabort(addr);
+}
+
+void __asan_load8(uintptr_t addr)
+{
+  __asan_load8_noabort(addr);
+}
+
+void __asan_store8(uintptr_t addr)
+{
+  __asan_store8_noabort(addr);
+}
+
+void __asan_load4(uintptr_t addr)
+{
+  __asan_load4_noabort(addr);
+}
+
+void __asan_store4(uintptr_t addr)
+{
+  __asan_store4_noabort(addr);
+}
+
+void __asan_load2(uintptr_t addr)
+{
+  __asan_load2_noabort(addr);
+}
+
+void __asan_store2(uintptr_t addr)
+{
+  __asan_store2_noabort(addr);
+}
+
+void __asan_load1(uintptr_t addr)
+{
+  __asan_load1_noabort(addr);
+}
+
+void __asan_store1(uintptr_t addr)
+{
+  __asan_store1_noabort(addr);
+}
diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h
new file mode 100644
index 0000000..c6fd07c
--- /dev/null
+++ b/mm/kasan/kasan.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+ * mm/kasan/kasan.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __MM_KASAN_KASAN_H
+#define __MM_KASAN_KASAN_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stddef.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_MM_KASAN
+#  define kasan_poison(addr, size)
+#  define kasan_unpoison(addr, size)
+#  define kasan_register(addr, size)
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+#ifdef CONFIG_MM_KASAN
+
+/****************************************************************************
+ * Name: kasan_poison
+ *
+ * Description:
+ *   Mark the memory range as inaccessible
+ *
+ * Input Parameters:
+ *   addr - range start address
+ *   size - range size
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+void kasan_poison(FAR const void *addr, size_t size);
+
+/****************************************************************************
+ * Name: kasan_unpoison
+ *
+ * Description:
+ *   Mark the memory range as accessible
+ *
+ * Input Parameters:
+ *   addr - range start address
+ *   size - range size
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+void kasan_unpoison(FAR const void *addr, size_t size);
+
+/****************************************************************************
+ * Name: kasan_register
+ *
+ * Description:
+ *   Monitor the memory range for invalid access check
+ *
+ * Input Parameters:
+ *   addr - range start address
+ *   size - range size
+ *
+ * Returned Value:
+ *   None.
+ *
+ * Note:
+ *   The size is shrinked for the shadow region
+ *
+ ****************************************************************************/
+
+void kasan_register(FAR void *addr, FAR size_t *size);
+
+#endif /* CONFIG_MM_KASAN */
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MM_KASAN_KASAN_H */
diff --git a/mm/mm_heap/mm_free.c b/mm/mm_heap/mm_free.c
index c3545cf..c788649 100644
--- a/mm/mm_heap/mm_free.c
+++ b/mm/mm_heap/mm_free.c
@@ -31,6 +31,7 @@
 #include <nuttx/mm/mm.h>
 
 #include "mm_heap/mm.h"
+#include "kasan/kasan.h"
 
 /****************************************************************************
  * Private Functions
@@ -83,8 +84,12 @@ void mm_free(FAR struct mm_heap_s *heap, FAR void *mem)
       return;
     }
 
+  kasan_poison(mem, mm_malloc_size(mem));
+
   if (mm_takesemaphore(heap) == false)
     {
+      kasan_unpoison(mem, mm_malloc_size(mem));
+
       /* We are in IDLE task & can't get sem, or meet -ESRCH return,
        * which means we are in situations during context switching(See
        * mm_takesemaphore() & getpid()). Then add to the delay list.
diff --git a/mm/mm_heap/mm_initialize.c b/mm/mm_heap/mm_initialize.c
index 9156111..4e2a21b 100644
--- a/mm/mm_heap/mm_initialize.c
+++ b/mm/mm_heap/mm_initialize.c
@@ -31,6 +31,7 @@
 #include <nuttx/mm/mm.h>
 
 #include "mm_heap/mm.h"
+#include "kasan/kasan.h"
 
 /****************************************************************************
  * Public Functions
@@ -86,6 +87,10 @@ void mm_addregion(FAR struct mm_heap_s *heap, FAR void *heapstart,
   DEBUGASSERT(heapsize <= MMSIZE_MAX + 1);
 #endif
 
+  /* Register to KASan for access check */
+
+  kasan_register(heapstart, &heapsize);
+
   DEBUGVERIFY(mm_takesemaphore(heap));
 
   /* Adjust the provided heap start and size so that they are both aligned
diff --git a/mm/mm_heap/mm_malloc.c b/mm/mm_heap/mm_malloc.c
index 598f553..a1262f5 100644
--- a/mm/mm_heap/mm_malloc.c
+++ b/mm/mm_heap/mm_malloc.c
@@ -32,6 +32,7 @@
 #include <nuttx/mm/mm.h>
 
 #include "mm_heap/mm.h"
+#include "kasan/kasan.h"
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -228,25 +229,20 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size)
   DEBUGASSERT(ret == NULL || mm_heapmember(heap, ret));
   mm_givesemaphore(heap);
 
-#ifdef CONFIG_MM_FILL_ALLOCATIONS
   if (ret)
     {
-       memset(ret, 0xaa, alignsize - SIZEOF_MM_ALLOCNODE);
-    }
+      kasan_unpoison(ret, mm_malloc_size(ret));
+#ifdef CONFIG_MM_FILL_ALLOCATIONS
+      memset(ret, 0xaa, alignsize - SIZEOF_MM_ALLOCNODE);
 #endif
-
-  /* If CONFIG_DEBUG_MM is defined, then output the result of the allocation
-   * to the SYSLOG.
-   */
-
 #ifdef CONFIG_DEBUG_MM
-  if (!ret)
-    {
-      mwarn("WARNING: Allocation failed, size %zu\n", alignsize);
+      minfo("Allocated %p, size %zu\n", ret, alignsize);
+#endif
     }
+#ifdef CONFIG_DEBUG_MM
   else
     {
-      minfo("Allocated %p, size %zu\n", ret, alignsize);
+      mwarn("WARNING: Allocation failed, size %zu\n", alignsize);
     }
 #endif
 
diff --git a/mm/mm_heap/mm_memalign.c b/mm/mm_heap/mm_memalign.c
index 9d1bdd6..1fcd387 100644
--- a/mm/mm_heap/mm_memalign.c
+++ b/mm/mm_heap/mm_memalign.c
@@ -29,6 +29,7 @@
 #include <nuttx/mm/mm.h>
 
 #include "mm_heap/mm.h"
+#include "kasan/kasan.h"
 
 /****************************************************************************
  * Public Functions
@@ -111,6 +112,8 @@ FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment,
       return NULL;
     }
 
+  kasan_poison((FAR void *)rawchunk, mm_malloc_size((FAR void *)rawchunk));
+
   /* We need to hold the MM semaphore while we muck with the chunks and
    * nodelist.
    */
@@ -219,5 +222,9 @@ FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment,
     }
 
   mm_givesemaphore(heap);
+
+  kasan_unpoison((FAR void *)alignedchunk,
+                 mm_malloc_size((FAR void *)alignedchunk));
+
   return (FAR void *)alignedchunk;
 }
diff --git a/mm/mm_heap/mm_realloc.c b/mm/mm_heap/mm_realloc.c
index 897201c..1842572 100644
--- a/mm/mm_heap/mm_realloc.c
+++ b/mm/mm_heap/mm_realloc.c
@@ -32,6 +32,7 @@
 #include <nuttx/mm/mm.h>
 
 #include "mm_heap/mm.h"
+#include "kasan/kasan.h"
 
 /****************************************************************************
  * Public Functions
@@ -123,6 +124,8 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
       if (newsize < oldsize)
         {
           mm_shrinkchunk(heap, oldnode, newsize);
+          kasan_poison((FAR char *)oldnode + oldnode->size,
+                       oldsize - oldnode->size);
         }
 
       /* Then return the original address */
@@ -264,12 +267,7 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
                                     (next->preceding & MM_ALLOC_BIT);
             }
 
-          /* Now we have to move the user contents 'down' in memory.  memcpy
-           * should be safe for this.
-           */
-
           newmem = (FAR void *)((FAR char *)newnode + SIZEOF_MM_ALLOCNODE);
-          memcpy(newmem, oldmem, oldsize - SIZEOF_MM_ALLOCNODE);
 
           /* Now we want to return newnode */
 
@@ -335,6 +333,17 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
         }
 
       mm_givesemaphore(heap);
+
+      kasan_unpoison(newmem, mm_malloc_size(newmem));
+      if (newmem != oldmem)
+        {
+          /* Now we have to move the user contents 'down' in memory.  memcpy
+           * should be safe for this.
+           */
+
+          memcpy(newmem, oldmem, oldsize - SIZEOF_MM_ALLOCNODE);
+        }
+
       return newmem;
     }
 
diff --git a/mm/umm_heap/umm_initialize.c b/mm/umm_heap/umm_initialize.c
index ca0fcc6..1eb726e 100644
--- a/mm/umm_heap/umm_initialize.c
+++ b/mm/umm_heap/umm_initialize.c
@@ -102,6 +102,7 @@ void umm_initialize(FAR void *heap_start, size_t heap_size)
 void umm_try_initialize(void)
 {
   uintptr_t allocbase;
+  size_t npages = 1;
 
   /* Return if the user heap is already initialized. */
 
@@ -110,16 +111,22 @@ void umm_try_initialize(void)
       return;
     }
 
-  /* Allocate one page. If we provide a zero brkaddr to pgalloc(),
+#ifdef CONFIG_MM_KASAN
+  /* we have to commit all memory for the shadow region */
+
+  npages = CONFIG_ARCH_HEAP_NPAGES;
+#endif
+
+  /* If we provide a zero brkaddr to pgalloc(),
    * it will create the first block in the correct virtual address
    * space and return the start address of that block.
    */
 
-  allocbase = pgalloc(0, 1);
+  allocbase = pgalloc(0, npages);
   DEBUGASSERT(allocbase != 0);
 
   /* Let umm_initialize do the real work. */
 
-  umm_initialize((FAR void *)allocbase, CONFIG_MM_PGSIZE);
+  umm_initialize((FAR void *)allocbase, npages * CONFIG_MM_PGSIZE);
 }
 #endif
diff --git a/tools/nxstyle.c b/tools/nxstyle.c
index ae0c288..f2b44fb 100644
--- a/tools/nxstyle.c
+++ b/tools/nxstyle.c
@@ -276,6 +276,15 @@ static const char *g_white_list[] =
   "SETATTR3resok",
   "FS3args",
 
+  /* Ref:
+   * mm/kasan/kasan.c
+   */
+
+  "__asan_loadN",
+  "__asan_storeN",
+  "__asan_loadN_noabort",
+  "__asan_storeN_noabort",
+
   NULL
 };