kfence, kasan: make KFENCE compatible with KASAN
authorAlexander Potapenko <glider@google.com>
Fri, 26 Feb 2021 01:19:21 +0000 (17:19 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 26 Feb 2021 17:41:02 +0000 (09:41 -0800)
Make KFENCE compatible with KASAN. Currently this helps test KFENCE
itself, where KASAN can catch potential corruptions to KFENCE state, or
other corruptions that may be a result of freepointer corruptions in the
main allocators.

[akpm@linux-foundation.org: merge fixup]
[andreyknvl@google.com: untag addresses for KFENCE]
Link: https://lkml.kernel.org/r/9dc196006921b191d25d10f6e611316db7da2efc.1611946152.git.andreyknvl@google.com
Link: https://lkml.kernel.org/r/20201103175841.3495947-7-elver@google.com
Signed-off-by: Marco Elver <elver@google.com>
Signed-off-by: Alexander Potapenko <glider@google.com>
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
Reviewed-by: Jann Horn <jannh@google.com>
Co-developed-by: Marco Elver <elver@google.com>
Cc: Andrey Konovalov <andreyknvl@google.com>
Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Christopher Lameter <cl@linux.com>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Hillf Danton <hdanton@sina.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Joern Engel <joern@purestorage.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Paul E. McKenney <paulmck@kernel.org>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: SeongJae Park <sjpark@amazon.de>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
lib/Kconfig.kfence
mm/kasan/common.c
mm/kasan/generic.c
mm/kasan/kasan.h
mm/kasan/shadow.c

index b88ac9d..edfecb5 100644 (file)
@@ -5,7 +5,7 @@ config HAVE_ARCH_KFENCE
 
 menuconfig KFENCE
        bool "KFENCE: low-overhead sampling-based memory safety error detector"
-       depends on HAVE_ARCH_KFENCE && !KASAN && (SLAB || SLUB)
+       depends on HAVE_ARCH_KFENCE && (SLAB || SLUB)
        select STACKTRACE
        help
          KFENCE is a low-overhead sampling-based detector of heap out-of-bounds
index b18189e..af1768c 100644 (file)
@@ -335,6 +335,9 @@ static bool ____kasan_slab_free(struct kmem_cache *cache, void *object,
        tagged_object = object;
        object = kasan_reset_tag(object);
 
+       if (is_kfence_address(object))
+               return false;
+
        if (unlikely(nearest_obj(cache, virt_to_head_page(object), object) !=
            object)) {
                kasan_report_invalid_free(tagged_object, ip);
@@ -413,6 +416,9 @@ static void *____kasan_kmalloc(struct kmem_cache *cache, const void *object,
        if (unlikely(object == NULL))
                return NULL;
 
+       if (is_kfence_address(kasan_reset_tag(object)))
+               return (void *)object;
+
        redzone_start = round_up((unsigned long)(object + size),
                                KASAN_GRANULE_SIZE);
        redzone_end = round_up((unsigned long)object + cache->object_size,
index 3f17a12..2e55e0f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/kasan.h>
 #include <linux/kernel.h>
+#include <linux/kfence.h>
 #include <linux/kmemleak.h>
 #include <linux/linkage.h>
 #include <linux/memblock.h>
@@ -331,7 +332,7 @@ void kasan_record_aux_stack(void *addr)
        struct kasan_alloc_meta *alloc_meta;
        void *object;
 
-       if (!(page && PageSlab(page)))
+       if (is_kfence_address(addr) || !(page && PageSlab(page)))
                return;
 
        cache = page->slab_cache;
index cc14b6e..fb88374 100644 (file)
@@ -3,6 +3,7 @@
 #define __MM_KASAN_KASAN_H
 
 #include <linux/kasan.h>
+#include <linux/kfence.h>
 #include <linux/stackdepot.h>
 
 #ifdef CONFIG_KASAN_HW_TAGS
@@ -331,14 +332,28 @@ static inline u8 kasan_random_tag(void) { return 0; }
 
 static inline void kasan_poison(const void *address, size_t size, u8 value)
 {
-       hw_set_mem_tag_range(kasan_reset_tag(address),
+       address = kasan_reset_tag(address);
+
+       /* Skip KFENCE memory if called explicitly outside of sl*b. */
+       if (is_kfence_address(address))
+               return;
+
+       hw_set_mem_tag_range((void *)address,
                        round_up(size, KASAN_GRANULE_SIZE), value);
 }
 
 static inline void kasan_unpoison(const void *address, size_t size)
 {
-       hw_set_mem_tag_range(kasan_reset_tag(address),
-                       round_up(size, KASAN_GRANULE_SIZE), get_tag(address));
+       u8 tag = get_tag(address);
+
+       address = kasan_reset_tag(address);
+
+       /* Skip KFENCE memory if called explicitly outside of sl*b. */
+       if (is_kfence_address(address))
+               return;
+
+       hw_set_mem_tag_range((void *)address,
+                       round_up(size, KASAN_GRANULE_SIZE), tag);
 }
 
 static inline bool kasan_byte_accessible(const void *addr)
index 80adc85..1372a2f 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/kasan.h>
 #include <linux/kernel.h>
+#include <linux/kfence.h>
 #include <linux/kmemleak.h>
 #include <linux/memory.h>
 #include <linux/mm.h>
@@ -84,6 +85,10 @@ void kasan_poison(const void *address, size_t size, u8 value)
        address = kasan_reset_tag(address);
        size = round_up(size, KASAN_GRANULE_SIZE);
 
+       /* Skip KFENCE memory if called explicitly outside of sl*b. */
+       if (is_kfence_address(address))
+               return;
+
        shadow_start = kasan_mem_to_shadow(address);
        shadow_end = kasan_mem_to_shadow(address + size);
 
@@ -102,6 +107,14 @@ void kasan_unpoison(const void *address, size_t size)
         */
        address = kasan_reset_tag(address);
 
+       /*
+        * Skip KFENCE memory if called explicitly outside of sl*b. Also note
+        * that calls to ksize(), where size is not a multiple of machine-word
+        * size, would otherwise poison the invalid portion of the word.
+        */
+       if (is_kfence_address(address))
+               return;
+
        kasan_poison(address, size, tag);
 
        if (size & KASAN_GRANULE_MASK) {