x86_64: kasan: add interceptors for memset/memmove/memcpy functions
authorAndrey Ryabinin <a.ryabinin@samsung.com>
Fri, 13 Feb 2015 22:39:56 +0000 (14:39 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 14 Feb 2015 05:21:41 +0000 (21:21 -0800)
Recently instrumentation of builtin functions calls was removed from GCC
5.0.  To check the memory accessed by such functions, userspace asan
always uses interceptors for them.

So now we should do this as well.  This patch declares
memset/memmove/memcpy as weak symbols.  In mm/kasan/kasan.c we have our
own implementation of those functions which checks memory before accessing
it.

Default memset/memmove/memcpy now now always have aliases with '__'
prefix.  For files that built without kasan instrumentation (e.g.
mm/slub.c) original mem* replaced (via #define) with prefixed variants,
cause we don't want to check memory accesses there.

Signed-off-by: Andrey Ryabinin <a.ryabinin@samsung.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Konstantin Serebryany <kcc@google.com>
Cc: Dmitry Chernenkov <dmitryc@google.com>
Signed-off-by: Andrey Konovalov <adech.fo@gmail.com>
Cc: Yuri Gribov <tetra2005@gmail.com>
Cc: Konstantin Khlebnikov <koct9i@gmail.com>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/x86/boot/compressed/eboot.c
arch/x86/boot/compressed/misc.h
arch/x86/include/asm/string_64.h
arch/x86/kernel/x8664_ksyms_64.c
arch/x86/lib/memcpy_64.S
arch/x86/lib/memmove_64.S
arch/x86/lib/memset_64.S
drivers/firmware/efi/libstub/efistub.h
mm/kasan/kasan.c

index 92b9a5f2aed6fcb73e0ac726b8fef95f8d93f6be..ef17683484e9b308e2cb89312258dfe1e62e2d72 100644 (file)
@@ -13,8 +13,7 @@
 #include <asm/setup.h>
 #include <asm/desc.h>
 
-#undef memcpy                  /* Use memcpy from misc.c */
-
+#include "../string.h"
 #include "eboot.h"
 
 static efi_system_table_t *sys_table;
index 24e3e569a13ce9bf1ba620811ff4b09d6fa6e32d..04477d68403f1fe6197d82276033ce27338c1bac 100644 (file)
@@ -7,6 +7,7 @@
  * we just keep it from happening
  */
 #undef CONFIG_PARAVIRT
+#undef CONFIG_KASAN
 #ifdef CONFIG_X86_32
 #define _ASM_X86_DESC_H 1
 #endif
index 19e2c468fc2c8045469ac2a704947cd07ea81100..e4661196994e86b189da7f6c2e84841d3dcdcb9b 100644 (file)
@@ -27,11 +27,12 @@ static __always_inline void *__inline_memcpy(void *to, const void *from, size_t
    function. */
 
 #define __HAVE_ARCH_MEMCPY 1
+extern void *__memcpy(void *to, const void *from, size_t len);
+
 #ifndef CONFIG_KMEMCHECK
 #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
 extern void *memcpy(void *to, const void *from, size_t len);
 #else
-extern void *__memcpy(void *to, const void *from, size_t len);
 #define memcpy(dst, src, len)                                  \
 ({                                                             \
        size_t __len = (len);                                   \
@@ -53,9 +54,11 @@ extern void *__memcpy(void *to, const void *from, size_t len);
 
 #define __HAVE_ARCH_MEMSET
 void *memset(void *s, int c, size_t n);
+void *__memset(void *s, int c, size_t n);
 
 #define __HAVE_ARCH_MEMMOVE
 void *memmove(void *dest, const void *src, size_t count);
+void *__memmove(void *dest, const void *src, size_t count);
 
 int memcmp(const void *cs, const void *ct, size_t count);
 size_t strlen(const char *s);
@@ -63,6 +66,19 @@ char *strcpy(char *dest, const char *src);
 char *strcat(char *dest, const char *src);
 int strcmp(const char *cs, const char *ct);
 
+#if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)
+
+/*
+ * For files that not instrumented (e.g. mm/slub.c) we
+ * should use not instrumented version of mem* functions.
+ */
+
+#undef memcpy
+#define memcpy(dst, src, len) __memcpy(dst, src, len)
+#define memmove(dst, src, len) __memmove(dst, src, len)
+#define memset(s, c, n) __memset(s, c, n)
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_X86_STRING_64_H */
index 040681928e9d971670eb1bab49b1c86e115dd55d..37d8fa4438f056b7611077a578a288d4250972b6 100644 (file)
@@ -50,13 +50,19 @@ EXPORT_SYMBOL(csum_partial);
 #undef memset
 #undef memmove
 
+extern void *__memset(void *, int, __kernel_size_t);
+extern void *__memcpy(void *, const void *, __kernel_size_t);
+extern void *__memmove(void *, const void *, __kernel_size_t);
 extern void *memset(void *, int, __kernel_size_t);
 extern void *memcpy(void *, const void *, __kernel_size_t);
-extern void *__memcpy(void *, const void *, __kernel_size_t);
+extern void *memmove(void *, const void *, __kernel_size_t);
+
+EXPORT_SYMBOL(__memset);
+EXPORT_SYMBOL(__memcpy);
+EXPORT_SYMBOL(__memmove);
 
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(__memcpy);
 EXPORT_SYMBOL(memmove);
 
 #ifndef CONFIG_DEBUG_VIRTUAL
index 56313a3261888d0e7eb866788c24f806acf5d47a..89b53c9968e7d50c1dd129dd92272f1a47edefe5 100644 (file)
@@ -53,6 +53,8 @@
 .Lmemcpy_e_e:
        .previous
 
+.weak memcpy
+
 ENTRY(__memcpy)
 ENTRY(memcpy)
        CFI_STARTPROC
@@ -199,8 +201,8 @@ ENDPROC(__memcpy)
         * only outcome...
         */
        .section .altinstructions, "a"
-       altinstruction_entry memcpy,.Lmemcpy_c,X86_FEATURE_REP_GOOD,\
+       altinstruction_entry __memcpy,.Lmemcpy_c,X86_FEATURE_REP_GOOD,\
                             .Lmemcpy_e-.Lmemcpy_c,.Lmemcpy_e-.Lmemcpy_c
-       altinstruction_entry memcpy,.Lmemcpy_c_e,X86_FEATURE_ERMS, \
+       altinstruction_entry __memcpy,.Lmemcpy_c_e,X86_FEATURE_ERMS, \
                             .Lmemcpy_e_e-.Lmemcpy_c_e,.Lmemcpy_e_e-.Lmemcpy_c_e
        .previous
index 65268a6104f45e09d5e45f75cb63edf6527164a0..9c4b530575da6e9b70cb8505f1e4b391b6fdff02 100644 (file)
  * Output:
  * rax: dest
  */
+.weak memmove
+
 ENTRY(memmove)
+ENTRY(__memmove)
        CFI_STARTPROC
 
        /* Handle more 32 bytes in loop */
@@ -220,4 +223,5 @@ ENTRY(memmove)
                .Lmemmove_end_forward-.Lmemmove_begin_forward,  \
                .Lmemmove_end_forward_efs-.Lmemmove_begin_forward_efs
        .previous
+ENDPROC(__memmove)
 ENDPROC(memmove)
index 2dcb3808cbdab6c91b9fbbf0d58790466780bb55..6f44935c6a606a1607022e889cc60ea151e54b65 100644 (file)
@@ -56,6 +56,8 @@
 .Lmemset_e_e:
        .previous
 
+.weak memset
+
 ENTRY(memset)
 ENTRY(__memset)
        CFI_STARTPROC
@@ -147,8 +149,8 @@ ENDPROC(__memset)
          * feature to implement the right patch order.
         */
        .section .altinstructions,"a"
-       altinstruction_entry memset,.Lmemset_c,X86_FEATURE_REP_GOOD,\
-                            .Lfinal-memset,.Lmemset_e-.Lmemset_c
-       altinstruction_entry memset,.Lmemset_c_e,X86_FEATURE_ERMS, \
-                            .Lfinal-memset,.Lmemset_e_e-.Lmemset_c_e
+       altinstruction_entry __memset,.Lmemset_c,X86_FEATURE_REP_GOOD,\
+                            .Lfinal-__memset,.Lmemset_e-.Lmemset_c
+       altinstruction_entry __memset,.Lmemset_c_e,X86_FEATURE_ERMS, \
+                            .Lfinal-__memset,.Lmemset_e_e-.Lmemset_c_e
        .previous
index 2be10984a67aaff647f0d6994627875d84593540..47437b16b18697c2d624eadd8513d9bdfa8f5299 100644 (file)
@@ -5,6 +5,10 @@
 /* error code which can't be mistaken for valid address */
 #define EFI_ERROR      (~0UL)
 
+#undef memcpy
+#undef memset
+#undef memmove
+
 void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
 
 efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image,
index dc83f070edb6cf1de238d4129ca97849f8944259..799c52b9826ca1667ffa858a0b10573afd95424c 100644 (file)
@@ -255,6 +255,35 @@ static __always_inline void check_memory_region(unsigned long addr,
        kasan_report(addr, size, write, _RET_IP_);
 }
 
+void __asan_loadN(unsigned long addr, size_t size);
+void __asan_storeN(unsigned long addr, size_t size);
+
+#undef memset
+void *memset(void *addr, int c, size_t len)
+{
+       __asan_storeN((unsigned long)addr, len);
+
+       return __memset(addr, c, len);
+}
+
+#undef memmove
+void *memmove(void *dest, const void *src, size_t len)
+{
+       __asan_loadN((unsigned long)src, len);
+       __asan_storeN((unsigned long)dest, len);
+
+       return __memmove(dest, src, len);
+}
+
+#undef memcpy
+void *memcpy(void *dest, const void *src, size_t len)
+{
+       __asan_loadN((unsigned long)src, len);
+       __asan_storeN((unsigned long)dest, len);
+
+       return __memcpy(dest, src, len);
+}
+
 void kasan_alloc_pages(struct page *page, unsigned int order)
 {
        if (likely(!PageHighMem(page)))