Skip to content

Commit

Permalink
kfence, kasan: make KFENCE compatible with KASAN
Browse files Browse the repository at this point in the history
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.

[[email protected]: merge fixup]
[[email protected]: untag addresses for KFENCE]
  Link: https://lkml.kernel.org/r/9dc196006921b191d25d10f6e611316db7da2efc.1611946152.git.andreyknvl@google.com

Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Marco Elver <[email protected]>
Signed-off-by: Alexander Potapenko <[email protected]>
Signed-off-by: Andrey Konovalov <[email protected]>
Reviewed-by: Dmitry Vyukov <[email protected]>
Reviewed-by: Jann Horn <[email protected]>
Co-developed-by: Marco Elver <[email protected]>
Cc: Andrey Konovalov <[email protected]>
Cc: Andrey Ryabinin <[email protected]>
Cc: Andy Lutomirski <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Catalin Marinas <[email protected]>
Cc: Christopher Lameter <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: David Rientjes <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Hillf Danton <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Joern Engel <[email protected]>
Cc: Jonathan Corbet <[email protected]>
Cc: Joonsoo Kim <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Pekka Enberg <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: SeongJae Park <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Vlastimil Babka <[email protected]>
Cc: Will Deacon <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
ramosian-glider authored and torvalds committed Feb 26, 2021
1 parent b89fb5e commit 2b83052
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 5 deletions.
2 changes: 1 addition & 1 deletion lib/Kconfig.kfence
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions mm/kasan/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion mm/kasan/generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand Down
21 changes: 18 additions & 3 deletions mm/kasan/kasan.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
13 changes: 13 additions & 0 deletions mm/kasan/shadow.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);

Expand All @@ -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) {
Expand Down

0 comments on commit 2b83052

Please sign in to comment.