Thread (18 messages) flat view 18 messages, 2 authors, 2021-02-09

Re: [PATCH v3 mm 08/13] kasan, mm: optimize krealloc poisoning

From: Andrey Konovalov <hidden>
Date: 2021-02-09 13:25:44
Also in: linux-arm-kernel, lkml

On Mon, Feb 8, 2021 at 11:48 AM Marco Elver [off-list ref] wrote:
On Fri, Feb 05, 2021 at 06:34PM +0100, Andrey Konovalov wrote:
quoted
Currently, krealloc() always calls ksize(), which unpoisons the whole
object including the redzone. This is inefficient, as kasan_krealloc()
repoisons the redzone for objects that fit into the same buffer.

This patch changes krealloc() instrumentation to use uninstrumented
__ksize() that doesn't unpoison the memory. Instead, kasan_kreallos()
is changed to unpoison the memory excluding the redzone.

For objects that don't fit into the old allocation, this patch disables
KASAN accessibility checks when copying memory into a new object instead
of unpoisoning it.

Signed-off-by: Andrey Konovalov <redacted>
Reviewed-by: Marco Elver <elver@google.com>

Clarification below.
quoted
---
 mm/kasan/common.c | 12 ++++++++++--
 mm/slab_common.c  | 20 ++++++++++++++------
 2 files changed, 24 insertions(+), 8 deletions(-)
diff --git a/mm/kasan/common.c b/mm/kasan/common.c
index 7ea643f7e69c..a8a67dca5e55 100644
--- a/mm/kasan/common.c
+++ b/mm/kasan/common.c
@@ -476,7 +476,7 @@ static void *____kasan_kmalloc(struct kmem_cache *cache, const void *object,

      /*
       * The object has already been unpoisoned by kasan_slab_alloc() for
-      * kmalloc() or by ksize() for krealloc().
+      * kmalloc() or by kasan_krealloc() for krealloc().
       */

      /*
@@ -526,7 +526,7 @@ void * __must_check __kasan_kmalloc_large(const void *ptr, size_t size,

      /*
       * The object has already been unpoisoned by kasan_alloc_pages() for
-      * alloc_pages() or by ksize() for krealloc().
+      * alloc_pages() or by kasan_krealloc() for krealloc().
       */

      /*
@@ -554,8 +554,16 @@ void * __must_check __kasan_krealloc(const void *object, size_t size, gfp_t flag
      if (unlikely(object == ZERO_SIZE_PTR))
              return (void *)object;

+     /*
+      * Unpoison the object's data.
+      * Part of it might already have been unpoisoned, but it's unknown
+      * how big that part is.
+      */
+     kasan_unpoison(object, size);
+
      page = virt_to_head_page(object);

+     /* Piggy-back on kmalloc() instrumentation to poison the redzone. */
      if (unlikely(!PageSlab(page)))
              return __kasan_kmalloc_large(object, size, flags);
      else
diff --git a/mm/slab_common.c b/mm/slab_common.c
index dad70239b54c..60a2f49df6ce 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -1140,19 +1140,27 @@ static __always_inline void *__do_krealloc(const void *p, size_t new_size,
      void *ret;
      size_t ks;

-     if (likely(!ZERO_OR_NULL_PTR(p)) && !kasan_check_byte(p))
-             return NULL;
-
-     ks = ksize(p);
+     /* Don't use instrumented ksize to allow precise KASAN poisoning. */
+     if (likely(!ZERO_OR_NULL_PTR(p))) {
+             if (!kasan_check_byte(p))
+                     return NULL;
Just checking: Check byte returns true if the object is not tracked by KASAN, right? I.e. if it's a KFENCE object, kasan_check_byte() always returns true.
kasan_check_byte() still performs the check, but since KFENCE objects
are never poisoned, the check always passes.

Thanks!
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help