summaryrefslogtreecommitdiff
path: root/mm/kasan
diff options
context:
space:
mode:
Diffstat (limited to 'mm/kasan')
-rw-r--r--mm/kasan/Makefile9
-rw-r--r--mm/kasan/kasan.h4
-rw-r--r--mm/kasan/kasan_test.c29
-rw-r--r--mm/kasan/shadow.c16
4 files changed, 56 insertions, 2 deletions
diff --git a/mm/kasan/Makefile b/mm/kasan/Makefile
index d4837bff3b60..7634dd2a6128 100644
--- a/mm/kasan/Makefile
+++ b/mm/kasan/Makefile
@@ -35,7 +35,14 @@ CFLAGS_shadow.o := $(CC_FLAGS_KASAN_RUNTIME)
CFLAGS_hw_tags.o := $(CC_FLAGS_KASAN_RUNTIME)
CFLAGS_sw_tags.o := $(CC_FLAGS_KASAN_RUNTIME)
-CFLAGS_KASAN_TEST := $(CFLAGS_KASAN) -fno-builtin $(call cc-disable-warning, vla)
+CFLAGS_KASAN_TEST := $(CFLAGS_KASAN) $(call cc-disable-warning, vla)
+ifndef CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX
+# If compiler instruments memintrinsics by prefixing them with __asan/__hwasan,
+# we need to treat them normally (as builtins), otherwise the compiler won't
+# recognize them as instrumentable. If it doesn't instrument them, we need to
+# pass -fno-builtin, so the compiler doesn't inline them.
+CFLAGS_KASAN_TEST += -fno-builtin
+endif
CFLAGS_kasan_test.o := $(CFLAGS_KASAN_TEST)
CFLAGS_kasan_test_module.o := $(CFLAGS_KASAN_TEST)
diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h
index 9377b0789edc..a61eeee3095a 100644
--- a/mm/kasan/kasan.h
+++ b/mm/kasan/kasan.h
@@ -666,4 +666,8 @@ void __hwasan_storeN_noabort(unsigned long addr, size_t size);
void __hwasan_tag_memory(unsigned long addr, u8 tag, unsigned long size);
+void *__hwasan_memset(void *addr, int c, size_t len);
+void *__hwasan_memmove(void *dest, const void *src, size_t len);
+void *__hwasan_memcpy(void *dest, const void *src, size_t len);
+
#endif /* __MM_KASAN_KASAN_H */
diff --git a/mm/kasan/kasan_test.c b/mm/kasan/kasan_test.c
index 74cd80c12b25..627eaf1ee1db 100644
--- a/mm/kasan/kasan_test.c
+++ b/mm/kasan/kasan_test.c
@@ -165,6 +165,15 @@ static void kasan_test_exit(struct kunit *test)
kunit_skip((test), "Test requires " #config "=n"); \
} while (0)
+#define KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test) do { \
+ if (IS_ENABLED(CONFIG_KASAN_HW_TAGS)) \
+ break; /* No compiler instrumentation. */ \
+ if (IS_ENABLED(CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX)) \
+ break; /* Should always be instrumented! */ \
+ if (IS_ENABLED(CONFIG_GENERIC_ENTRY)) \
+ kunit_skip((test), "Test requires checked mem*()"); \
+} while (0)
+
static void kmalloc_oob_right(struct kunit *test)
{
char *ptr;
@@ -454,6 +463,8 @@ static void kmalloc_oob_16(struct kunit *test)
u64 words[2];
} *ptr1, *ptr2;
+ KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
+
/* This test is specifically crafted for the generic mode. */
KASAN_TEST_NEEDS_CONFIG_ON(test, CONFIG_KASAN_GENERIC);
@@ -476,6 +487,8 @@ static void kmalloc_uaf_16(struct kunit *test)
u64 words[2];
} *ptr1, *ptr2;
+ KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
+
ptr1 = kmalloc(sizeof(*ptr1), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr1);
@@ -498,6 +511,8 @@ static void kmalloc_oob_memset_2(struct kunit *test)
char *ptr;
size_t size = 128 - KASAN_GRANULE_SIZE;
+ KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
+
ptr = kmalloc(size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
@@ -511,6 +526,8 @@ static void kmalloc_oob_memset_4(struct kunit *test)
char *ptr;
size_t size = 128 - KASAN_GRANULE_SIZE;
+ KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
+
ptr = kmalloc(size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
@@ -524,6 +541,8 @@ static void kmalloc_oob_memset_8(struct kunit *test)
char *ptr;
size_t size = 128 - KASAN_GRANULE_SIZE;
+ KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
+
ptr = kmalloc(size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
@@ -537,6 +556,8 @@ static void kmalloc_oob_memset_16(struct kunit *test)
char *ptr;
size_t size = 128 - KASAN_GRANULE_SIZE;
+ KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
+
ptr = kmalloc(size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
@@ -550,6 +571,8 @@ static void kmalloc_oob_in_memset(struct kunit *test)
char *ptr;
size_t size = 128 - KASAN_GRANULE_SIZE;
+ KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
+
ptr = kmalloc(size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
@@ -566,6 +589,8 @@ static void kmalloc_memmove_negative_size(struct kunit *test)
size_t size = 64;
size_t invalid_size = -2;
+ KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
+
/*
* Hardware tag-based mode doesn't check memmove for negative size.
* As a result, this test introduces a side-effect memory corruption,
@@ -590,6 +615,8 @@ static void kmalloc_memmove_invalid_size(struct kunit *test)
size_t size = 64;
size_t invalid_size = size;
+ KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
+
ptr = kmalloc(size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr);
@@ -618,6 +645,8 @@ static void kmalloc_uaf_memset(struct kunit *test)
char *ptr;
size_t size = 33;
+ KASAN_TEST_NEEDS_CHECKED_MEMINTRINSICS(test);
+
/*
* Only generic KASAN uses quarantine, which is required to avoid a
* kernel memory corruption this test causes.
diff --git a/mm/kasan/shadow.c b/mm/kasan/shadow.c
index 3703983a8e55..c8b86f3273b5 100644
--- a/mm/kasan/shadow.c
+++ b/mm/kasan/shadow.c
@@ -38,11 +38,14 @@ bool __kasan_check_write(const volatile void *p, unsigned int size)
}
EXPORT_SYMBOL(__kasan_check_write);
-#ifndef CONFIG_GENERIC_ENTRY
+#if !defined(CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX) && !defined(CONFIG_GENERIC_ENTRY)
/*
* CONFIG_GENERIC_ENTRY relies on compiler emitted mem*() calls to not be
* instrumented. KASAN enabled toolchains should emit __asan_mem*() functions
* for the sites they want to instrument.
+ *
+ * If we have a compiler that can instrument meminstrinsics, never override
+ * these, so that non-instrumented files can safely consider them as builtins.
*/
#undef memset
void *memset(void *addr, int c, size_t len)
@@ -107,6 +110,17 @@ void *__asan_memcpy(void *dest, const void *src, size_t len)
}
EXPORT_SYMBOL(__asan_memcpy);
+#ifdef CONFIG_KASAN_SW_TAGS
+void *__hwasan_memset(void *addr, int c, size_t len) __alias(__asan_memset);
+EXPORT_SYMBOL(__hwasan_memset);
+#ifdef __HAVE_ARCH_MEMMOVE
+void *__hwasan_memmove(void *dest, const void *src, size_t len) __alias(__asan_memmove);
+EXPORT_SYMBOL(__hwasan_memmove);
+#endif
+void *__hwasan_memcpy(void *dest, const void *src, size_t len) __alias(__asan_memcpy);
+EXPORT_SYMBOL(__hwasan_memcpy);
+#endif
+
void kasan_poison(const void *addr, size_t size, u8 value, bool init)
{
void *shadow_start, *shadow_end;