kasan: rename report and tags files
authorAndrey Konovalov <andreyknvl@google.com>
Tue, 22 Dec 2020 20:00:39 +0000 (12:00 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 22 Dec 2020 20:55:06 +0000 (12:55 -0800)
Rename generic_report.c to report_generic.c and tags_report.c to
report_sw_tags.c, as their content is more relevant to report.c file.
Also rename tags.c to sw_tags.c to better reflect that this file contains
code for software tag-based mode.

No functional changes.

Link: https://lkml.kernel.org/r/a6105d416da97d389580015afed66c4c3cfd4c08.1606161801.git.andreyknvl@google.com
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Reviewed-by: Marco Elver <elver@google.com>
Reviewed-by: Alexander Potapenko <glider@google.com>
Tested-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Branislav Rankov <Branislav.Rankov@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Evgenii Stepanov <eugenis@google.com>
Cc: Kevin Brodsky <kevin.brodsky@arm.com>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
mm/kasan/Makefile
mm/kasan/generic_report.c [deleted file]
mm/kasan/report.c
mm/kasan/report_generic.c [new file with mode: 0644]
mm/kasan/report_sw_tags.c [new file with mode: 0644]
mm/kasan/sw_tags.c [new file with mode: 0644]
mm/kasan/tags.c [deleted file]
mm/kasan/tags_report.c [deleted file]

index 7cc1031..f1d68a3 100644 (file)
@@ -6,13 +6,13 @@ KCOV_INSTRUMENT := n
 # Disable ftrace to avoid recursion.
 CFLAGS_REMOVE_common.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_generic.o = $(CC_FLAGS_FTRACE)
 # Disable ftrace to avoid recursion.
 CFLAGS_REMOVE_common.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_generic.o = $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_generic_report.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_init.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_quarantine.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_report.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_init.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_quarantine.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_report.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_report_generic.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_report_sw_tags.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_shadow.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_shadow.o = $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_tags.o = $(CC_FLAGS_FTRACE)
-CFLAGS_REMOVE_tags_report.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_sw_tags.o = $(CC_FLAGS_FTRACE)
 
 # Function splitter causes unnecessary splits in __asan_load1/__asan_store1
 # see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63533
 
 # Function splitter causes unnecessary splits in __asan_load1/__asan_store1
 # see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63533
@@ -23,14 +23,14 @@ CC_FLAGS_KASAN_RUNTIME += -DDISABLE_BRANCH_PROFILING
 
 CFLAGS_common.o := $(CC_FLAGS_KASAN_RUNTIME)
 CFLAGS_generic.o := $(CC_FLAGS_KASAN_RUNTIME)
 
 CFLAGS_common.o := $(CC_FLAGS_KASAN_RUNTIME)
 CFLAGS_generic.o := $(CC_FLAGS_KASAN_RUNTIME)
-CFLAGS_generic_report.o := $(CC_FLAGS_KASAN_RUNTIME)
 CFLAGS_init.o := $(CC_FLAGS_KASAN_RUNTIME)
 CFLAGS_quarantine.o := $(CC_FLAGS_KASAN_RUNTIME)
 CFLAGS_report.o := $(CC_FLAGS_KASAN_RUNTIME)
 CFLAGS_init.o := $(CC_FLAGS_KASAN_RUNTIME)
 CFLAGS_quarantine.o := $(CC_FLAGS_KASAN_RUNTIME)
 CFLAGS_report.o := $(CC_FLAGS_KASAN_RUNTIME)
+CFLAGS_report_generic.o := $(CC_FLAGS_KASAN_RUNTIME)
+CFLAGS_report_sw_tags.o := $(CC_FLAGS_KASAN_RUNTIME)
 CFLAGS_shadow.o := $(CC_FLAGS_KASAN_RUNTIME)
 CFLAGS_shadow.o := $(CC_FLAGS_KASAN_RUNTIME)
-CFLAGS_tags.o := $(CC_FLAGS_KASAN_RUNTIME)
-CFLAGS_tags_report.o := $(CC_FLAGS_KASAN_RUNTIME)
+CFLAGS_sw_tags.o := $(CC_FLAGS_KASAN_RUNTIME)
 
 obj-$(CONFIG_KASAN) := common.o report.o
 
 obj-$(CONFIG_KASAN) := common.o report.o
-obj-$(CONFIG_KASAN_GENERIC) += init.o generic.o generic_report.o shadow.o quarantine.o
-obj-$(CONFIG_KASAN_SW_TAGS) += init.o shadow.o tags.o tags_report.o
+obj-$(CONFIG_KASAN_GENERIC) += init.o generic.o report_generic.o shadow.o quarantine.o
+obj-$(CONFIG_KASAN_SW_TAGS) += init.o report_sw_tags.o shadow.o sw_tags.o
diff --git a/mm/kasan/generic_report.c b/mm/kasan/generic_report.c
deleted file mode 100644 (file)
index 7d5b9e5..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * This file contains generic KASAN specific error reporting code.
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
- *
- * Some code borrowed from https://github.com/xairy/kasan-prototype by
- *        Andrey Konovalov <andreyknvl@gmail.com>
- */
-
-#include <linux/bitops.h>
-#include <linux/ftrace.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/printk.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/stackdepot.h>
-#include <linux/stacktrace.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/kasan.h>
-#include <linux/module.h>
-
-#include <asm/sections.h>
-
-#include "kasan.h"
-#include "../slab.h"
-
-void *find_first_bad_addr(void *addr, size_t size)
-{
-       void *p = addr;
-
-       while (p < addr + size && !(*(u8 *)kasan_mem_to_shadow(p)))
-               p += KASAN_GRANULE_SIZE;
-       return p;
-}
-
-static const char *get_shadow_bug_type(struct kasan_access_info *info)
-{
-       const char *bug_type = "unknown-crash";
-       u8 *shadow_addr;
-
-       shadow_addr = (u8 *)kasan_mem_to_shadow(info->first_bad_addr);
-
-       /*
-        * If shadow byte value is in [0, KASAN_GRANULE_SIZE) we can look
-        * at the next shadow byte to determine the type of the bad access.
-        */
-       if (*shadow_addr > 0 && *shadow_addr <= KASAN_GRANULE_SIZE - 1)
-               shadow_addr++;
-
-       switch (*shadow_addr) {
-       case 0 ... KASAN_GRANULE_SIZE - 1:
-               /*
-                * In theory it's still possible to see these shadow values
-                * due to a data race in the kernel code.
-                */
-               bug_type = "out-of-bounds";
-               break;
-       case KASAN_PAGE_REDZONE:
-       case KASAN_KMALLOC_REDZONE:
-               bug_type = "slab-out-of-bounds";
-               break;
-       case KASAN_GLOBAL_REDZONE:
-               bug_type = "global-out-of-bounds";
-               break;
-       case KASAN_STACK_LEFT:
-       case KASAN_STACK_MID:
-       case KASAN_STACK_RIGHT:
-       case KASAN_STACK_PARTIAL:
-               bug_type = "stack-out-of-bounds";
-               break;
-       case KASAN_FREE_PAGE:
-       case KASAN_KMALLOC_FREE:
-       case KASAN_KMALLOC_FREETRACK:
-               bug_type = "use-after-free";
-               break;
-       case KASAN_ALLOCA_LEFT:
-       case KASAN_ALLOCA_RIGHT:
-               bug_type = "alloca-out-of-bounds";
-               break;
-       case KASAN_VMALLOC_INVALID:
-               bug_type = "vmalloc-out-of-bounds";
-               break;
-       }
-
-       return bug_type;
-}
-
-static const char *get_wild_bug_type(struct kasan_access_info *info)
-{
-       const char *bug_type = "unknown-crash";
-
-       if ((unsigned long)info->access_addr < PAGE_SIZE)
-               bug_type = "null-ptr-deref";
-       else if ((unsigned long)info->access_addr < TASK_SIZE)
-               bug_type = "user-memory-access";
-       else
-               bug_type = "wild-memory-access";
-
-       return bug_type;
-}
-
-const char *get_bug_type(struct kasan_access_info *info)
-{
-       /*
-        * If access_size is a negative number, then it has reason to be
-        * defined as out-of-bounds bug type.
-        *
-        * Casting negative numbers to size_t would indeed turn up as
-        * a large size_t and its value will be larger than ULONG_MAX/2,
-        * so that this can qualify as out-of-bounds.
-        */
-       if (info->access_addr + info->access_size < info->access_addr)
-               return "out-of-bounds";
-
-       if (addr_has_shadow(info->access_addr))
-               return get_shadow_bug_type(info);
-       return get_wild_bug_type(info);
-}
-
-#define DEFINE_ASAN_REPORT_LOAD(size)                     \
-void __asan_report_load##size##_noabort(unsigned long addr) \
-{                                                         \
-       kasan_report(addr, size, false, _RET_IP_);        \
-}                                                         \
-EXPORT_SYMBOL(__asan_report_load##size##_noabort)
-
-#define DEFINE_ASAN_REPORT_STORE(size)                     \
-void __asan_report_store##size##_noabort(unsigned long addr) \
-{                                                          \
-       kasan_report(addr, size, true, _RET_IP_);          \
-}                                                          \
-EXPORT_SYMBOL(__asan_report_store##size##_noabort)
-
-DEFINE_ASAN_REPORT_LOAD(1);
-DEFINE_ASAN_REPORT_LOAD(2);
-DEFINE_ASAN_REPORT_LOAD(4);
-DEFINE_ASAN_REPORT_LOAD(8);
-DEFINE_ASAN_REPORT_LOAD(16);
-DEFINE_ASAN_REPORT_STORE(1);
-DEFINE_ASAN_REPORT_STORE(2);
-DEFINE_ASAN_REPORT_STORE(4);
-DEFINE_ASAN_REPORT_STORE(8);
-DEFINE_ASAN_REPORT_STORE(16);
-
-void __asan_report_load_n_noabort(unsigned long addr, size_t size)
-{
-       kasan_report(addr, size, false, _RET_IP_);
-}
-EXPORT_SYMBOL(__asan_report_load_n_noabort);
-
-void __asan_report_store_n_noabort(unsigned long addr, size_t size)
-{
-       kasan_report(addr, size, true, _RET_IP_);
-}
-EXPORT_SYMBOL(__asan_report_store_n_noabort);
index d16ccbc..96a7004 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
 // SPDX-License-Identifier: GPL-2.0
 /*
- * This file contains common generic and tag-based KASAN error reporting code.
+ * This file contains common KASAN error reporting code.
  *
  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
  * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
  *
  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
  * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
diff --git a/mm/kasan/report_generic.c b/mm/kasan/report_generic.c
new file mode 100644 (file)
index 0000000..7d5b9e5
--- /dev/null
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file contains generic KASAN specific error reporting code.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
+ *
+ * Some code borrowed from https://github.com/xairy/kasan-prototype by
+ *        Andrey Konovalov <andreyknvl@gmail.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/ftrace.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/printk.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/stackdepot.h>
+#include <linux/stacktrace.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/kasan.h>
+#include <linux/module.h>
+
+#include <asm/sections.h>
+
+#include "kasan.h"
+#include "../slab.h"
+
+void *find_first_bad_addr(void *addr, size_t size)
+{
+       void *p = addr;
+
+       while (p < addr + size && !(*(u8 *)kasan_mem_to_shadow(p)))
+               p += KASAN_GRANULE_SIZE;
+       return p;
+}
+
+static const char *get_shadow_bug_type(struct kasan_access_info *info)
+{
+       const char *bug_type = "unknown-crash";
+       u8 *shadow_addr;
+
+       shadow_addr = (u8 *)kasan_mem_to_shadow(info->first_bad_addr);
+
+       /*
+        * If shadow byte value is in [0, KASAN_GRANULE_SIZE) we can look
+        * at the next shadow byte to determine the type of the bad access.
+        */
+       if (*shadow_addr > 0 && *shadow_addr <= KASAN_GRANULE_SIZE - 1)
+               shadow_addr++;
+
+       switch (*shadow_addr) {
+       case 0 ... KASAN_GRANULE_SIZE - 1:
+               /*
+                * In theory it's still possible to see these shadow values
+                * due to a data race in the kernel code.
+                */
+               bug_type = "out-of-bounds";
+               break;
+       case KASAN_PAGE_REDZONE:
+       case KASAN_KMALLOC_REDZONE:
+               bug_type = "slab-out-of-bounds";
+               break;
+       case KASAN_GLOBAL_REDZONE:
+               bug_type = "global-out-of-bounds";
+               break;
+       case KASAN_STACK_LEFT:
+       case KASAN_STACK_MID:
+       case KASAN_STACK_RIGHT:
+       case KASAN_STACK_PARTIAL:
+               bug_type = "stack-out-of-bounds";
+               break;
+       case KASAN_FREE_PAGE:
+       case KASAN_KMALLOC_FREE:
+       case KASAN_KMALLOC_FREETRACK:
+               bug_type = "use-after-free";
+               break;
+       case KASAN_ALLOCA_LEFT:
+       case KASAN_ALLOCA_RIGHT:
+               bug_type = "alloca-out-of-bounds";
+               break;
+       case KASAN_VMALLOC_INVALID:
+               bug_type = "vmalloc-out-of-bounds";
+               break;
+       }
+
+       return bug_type;
+}
+
+static const char *get_wild_bug_type(struct kasan_access_info *info)
+{
+       const char *bug_type = "unknown-crash";
+
+       if ((unsigned long)info->access_addr < PAGE_SIZE)
+               bug_type = "null-ptr-deref";
+       else if ((unsigned long)info->access_addr < TASK_SIZE)
+               bug_type = "user-memory-access";
+       else
+               bug_type = "wild-memory-access";
+
+       return bug_type;
+}
+
+const char *get_bug_type(struct kasan_access_info *info)
+{
+       /*
+        * If access_size is a negative number, then it has reason to be
+        * defined as out-of-bounds bug type.
+        *
+        * Casting negative numbers to size_t would indeed turn up as
+        * a large size_t and its value will be larger than ULONG_MAX/2,
+        * so that this can qualify as out-of-bounds.
+        */
+       if (info->access_addr + info->access_size < info->access_addr)
+               return "out-of-bounds";
+
+       if (addr_has_shadow(info->access_addr))
+               return get_shadow_bug_type(info);
+       return get_wild_bug_type(info);
+}
+
+#define DEFINE_ASAN_REPORT_LOAD(size)                     \
+void __asan_report_load##size##_noabort(unsigned long addr) \
+{                                                         \
+       kasan_report(addr, size, false, _RET_IP_);        \
+}                                                         \
+EXPORT_SYMBOL(__asan_report_load##size##_noabort)
+
+#define DEFINE_ASAN_REPORT_STORE(size)                     \
+void __asan_report_store##size##_noabort(unsigned long addr) \
+{                                                          \
+       kasan_report(addr, size, true, _RET_IP_);          \
+}                                                          \
+EXPORT_SYMBOL(__asan_report_store##size##_noabort)
+
+DEFINE_ASAN_REPORT_LOAD(1);
+DEFINE_ASAN_REPORT_LOAD(2);
+DEFINE_ASAN_REPORT_LOAD(4);
+DEFINE_ASAN_REPORT_LOAD(8);
+DEFINE_ASAN_REPORT_LOAD(16);
+DEFINE_ASAN_REPORT_STORE(1);
+DEFINE_ASAN_REPORT_STORE(2);
+DEFINE_ASAN_REPORT_STORE(4);
+DEFINE_ASAN_REPORT_STORE(8);
+DEFINE_ASAN_REPORT_STORE(16);
+
+void __asan_report_load_n_noabort(unsigned long addr, size_t size)
+{
+       kasan_report(addr, size, false, _RET_IP_);
+}
+EXPORT_SYMBOL(__asan_report_load_n_noabort);
+
+void __asan_report_store_n_noabort(unsigned long addr, size_t size)
+{
+       kasan_report(addr, size, true, _RET_IP_);
+}
+EXPORT_SYMBOL(__asan_report_store_n_noabort);
diff --git a/mm/kasan/report_sw_tags.c b/mm/kasan/report_sw_tags.c
new file mode 100644 (file)
index 0000000..c87d5a3
--- /dev/null
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file contains tag-based KASAN specific error reporting code.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
+ *
+ * Some code borrowed from https://github.com/xairy/kasan-prototype by
+ *        Andrey Konovalov <andreyknvl@gmail.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/ftrace.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/printk.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/stackdepot.h>
+#include <linux/stacktrace.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/kasan.h>
+#include <linux/module.h>
+
+#include <asm/sections.h>
+
+#include "kasan.h"
+#include "../slab.h"
+
+const char *get_bug_type(struct kasan_access_info *info)
+{
+#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY
+       struct kasan_alloc_meta *alloc_meta;
+       struct kmem_cache *cache;
+       struct page *page;
+       const void *addr;
+       void *object;
+       u8 tag;
+       int i;
+
+       tag = get_tag(info->access_addr);
+       addr = reset_tag(info->access_addr);
+       page = kasan_addr_to_page(addr);
+       if (page && PageSlab(page)) {
+               cache = page->slab_cache;
+               object = nearest_obj(cache, page, (void *)addr);
+               alloc_meta = get_alloc_info(cache, object);
+
+               for (i = 0; i < KASAN_NR_FREE_STACKS; i++)
+                       if (alloc_meta->free_pointer_tag[i] == tag)
+                               return "use-after-free";
+               return "out-of-bounds";
+       }
+
+#endif
+       /*
+        * If access_size is a negative number, then it has reason to be
+        * defined as out-of-bounds bug type.
+        *
+        * Casting negative numbers to size_t would indeed turn up as
+        * a large size_t and its value will be larger than ULONG_MAX/2,
+        * so that this can qualify as out-of-bounds.
+        */
+       if (info->access_addr + info->access_size < info->access_addr)
+               return "out-of-bounds";
+
+       return "invalid-access";
+}
+
+void *find_first_bad_addr(void *addr, size_t size)
+{
+       u8 tag = get_tag(addr);
+       void *p = reset_tag(addr);
+       void *end = p + size;
+
+       while (p < end && tag == *(u8 *)kasan_mem_to_shadow(p))
+               p += KASAN_GRANULE_SIZE;
+       return p;
+}
+
+void print_tags(u8 addr_tag, const void *addr)
+{
+       u8 *shadow = (u8 *)kasan_mem_to_shadow(addr);
+
+       pr_err("Pointer tag: [%02x], memory tag: [%02x]\n", addr_tag, *shadow);
+}
diff --git a/mm/kasan/sw_tags.c b/mm/kasan/sw_tags.c
new file mode 100644 (file)
index 0000000..c0b3f32
--- /dev/null
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file contains core tag-based KASAN code.
+ *
+ * Copyright (c) 2018 Google, Inc.
+ * Author: Andrey Konovalov <andreyknvl@google.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/export.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/kasan.h>
+#include <linux/kernel.h>
+#include <linux/kmemleak.h>
+#include <linux/linkage.h>
+#include <linux/memblock.h>
+#include <linux/memory.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/sched/task_stack.h>
+#include <linux/slab.h>
+#include <linux/stacktrace.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/bug.h>
+
+#include "kasan.h"
+#include "../slab.h"
+
+static DEFINE_PER_CPU(u32, prng_state);
+
+void kasan_init_tags(void)
+{
+       int cpu;
+
+       for_each_possible_cpu(cpu)
+               per_cpu(prng_state, cpu) = (u32)get_cycles();
+}
+
+/*
+ * If a preemption happens between this_cpu_read and this_cpu_write, the only
+ * side effect is that we'll give a few allocated in different contexts objects
+ * the same tag. Since tag-based KASAN is meant to be used a probabilistic
+ * bug-detection debug feature, this doesn't have significant negative impact.
+ *
+ * Ideally the tags use strong randomness to prevent any attempts to predict
+ * them during explicit exploit attempts. But strong randomness is expensive,
+ * and we did an intentional trade-off to use a PRNG. This non-atomic RMW
+ * sequence has in fact positive effect, since interrupts that randomly skew
+ * PRNG at unpredictable points do only good.
+ */
+u8 random_tag(void)
+{
+       u32 state = this_cpu_read(prng_state);
+
+       state = 1664525 * state + 1013904223;
+       this_cpu_write(prng_state, state);
+
+       return (u8)(state % (KASAN_TAG_MAX + 1));
+}
+
+void *kasan_reset_tag(const void *addr)
+{
+       return reset_tag(addr);
+}
+
+bool check_memory_region(unsigned long addr, size_t size, bool write,
+                               unsigned long ret_ip)
+{
+       u8 tag;
+       u8 *shadow_first, *shadow_last, *shadow;
+       void *untagged_addr;
+
+       if (unlikely(size == 0))
+               return true;
+
+       if (unlikely(addr + size < addr))
+               return !kasan_report(addr, size, write, ret_ip);
+
+       tag = get_tag((const void *)addr);
+
+       /*
+        * Ignore accesses for pointers tagged with 0xff (native kernel
+        * pointer tag) to suppress false positives caused by kmap.
+        *
+        * Some kernel code was written to account for archs that don't keep
+        * high memory mapped all the time, but rather map and unmap particular
+        * pages when needed. Instead of storing a pointer to the kernel memory,
+        * this code saves the address of the page structure and offset within
+        * that page for later use. Those pages are then mapped and unmapped
+        * with kmap/kunmap when necessary and virt_to_page is used to get the
+        * virtual address of the page. For arm64 (that keeps the high memory
+        * mapped all the time), kmap is turned into a page_address call.
+
+        * The issue is that with use of the page_address + virt_to_page
+        * sequence the top byte value of the original pointer gets lost (gets
+        * set to KASAN_TAG_KERNEL (0xFF)).
+        */
+       if (tag == KASAN_TAG_KERNEL)
+               return true;
+
+       untagged_addr = reset_tag((const void *)addr);
+       if (unlikely(untagged_addr <
+                       kasan_shadow_to_mem((void *)KASAN_SHADOW_START))) {
+               return !kasan_report(addr, size, write, ret_ip);
+       }
+       shadow_first = kasan_mem_to_shadow(untagged_addr);
+       shadow_last = kasan_mem_to_shadow(untagged_addr + size - 1);
+       for (shadow = shadow_first; shadow <= shadow_last; shadow++) {
+               if (*shadow != tag) {
+                       return !kasan_report(addr, size, write, ret_ip);
+               }
+       }
+
+       return true;
+}
+
+#define DEFINE_HWASAN_LOAD_STORE(size)                                 \
+       void __hwasan_load##size##_noabort(unsigned long addr)          \
+       {                                                               \
+               check_memory_region(addr, size, false, _RET_IP_);       \
+       }                                                               \
+       EXPORT_SYMBOL(__hwasan_load##size##_noabort);                   \
+       void __hwasan_store##size##_noabort(unsigned long addr)         \
+       {                                                               \
+               check_memory_region(addr, size, true, _RET_IP_);        \
+       }                                                               \
+       EXPORT_SYMBOL(__hwasan_store##size##_noabort)
+
+DEFINE_HWASAN_LOAD_STORE(1);
+DEFINE_HWASAN_LOAD_STORE(2);
+DEFINE_HWASAN_LOAD_STORE(4);
+DEFINE_HWASAN_LOAD_STORE(8);
+DEFINE_HWASAN_LOAD_STORE(16);
+
+void __hwasan_loadN_noabort(unsigned long addr, unsigned long size)
+{
+       check_memory_region(addr, size, false, _RET_IP_);
+}
+EXPORT_SYMBOL(__hwasan_loadN_noabort);
+
+void __hwasan_storeN_noabort(unsigned long addr, unsigned long size)
+{
+       check_memory_region(addr, size, true, _RET_IP_);
+}
+EXPORT_SYMBOL(__hwasan_storeN_noabort);
+
+void __hwasan_tag_memory(unsigned long addr, u8 tag, unsigned long size)
+{
+       poison_range((void *)addr, size, tag);
+}
+EXPORT_SYMBOL(__hwasan_tag_memory);
+
+void kasan_set_free_info(struct kmem_cache *cache,
+                               void *object, u8 tag)
+{
+       struct kasan_alloc_meta *alloc_meta;
+       u8 idx = 0;
+
+       alloc_meta = get_alloc_info(cache, object);
+
+#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY
+       idx = alloc_meta->free_track_idx;
+       alloc_meta->free_pointer_tag[idx] = tag;
+       alloc_meta->free_track_idx = (idx + 1) % KASAN_NR_FREE_STACKS;
+#endif
+
+       kasan_set_track(&alloc_meta->free_track[idx], GFP_NOWAIT);
+}
+
+struct kasan_track *kasan_get_free_track(struct kmem_cache *cache,
+                               void *object, u8 tag)
+{
+       struct kasan_alloc_meta *alloc_meta;
+       int i = 0;
+
+       alloc_meta = get_alloc_info(cache, object);
+
+#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY
+       for (i = 0; i < KASAN_NR_FREE_STACKS; i++) {
+               if (alloc_meta->free_pointer_tag[i] == tag)
+                       break;
+       }
+       if (i == KASAN_NR_FREE_STACKS)
+               i = alloc_meta->free_track_idx;
+#endif
+
+       return &alloc_meta->free_track[i];
+}
diff --git a/mm/kasan/tags.c b/mm/kasan/tags.c
deleted file mode 100644 (file)
index c0b3f32..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * This file contains core tag-based KASAN code.
- *
- * Copyright (c) 2018 Google, Inc.
- * Author: Andrey Konovalov <andreyknvl@google.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/export.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/kasan.h>
-#include <linux/kernel.h>
-#include <linux/kmemleak.h>
-#include <linux/linkage.h>
-#include <linux/memblock.h>
-#include <linux/memory.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/printk.h>
-#include <linux/random.h>
-#include <linux/sched.h>
-#include <linux/sched/task_stack.h>
-#include <linux/slab.h>
-#include <linux/stacktrace.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-#include <linux/bug.h>
-
-#include "kasan.h"
-#include "../slab.h"
-
-static DEFINE_PER_CPU(u32, prng_state);
-
-void kasan_init_tags(void)
-{
-       int cpu;
-
-       for_each_possible_cpu(cpu)
-               per_cpu(prng_state, cpu) = (u32)get_cycles();
-}
-
-/*
- * If a preemption happens between this_cpu_read and this_cpu_write, the only
- * side effect is that we'll give a few allocated in different contexts objects
- * the same tag. Since tag-based KASAN is meant to be used a probabilistic
- * bug-detection debug feature, this doesn't have significant negative impact.
- *
- * Ideally the tags use strong randomness to prevent any attempts to predict
- * them during explicit exploit attempts. But strong randomness is expensive,
- * and we did an intentional trade-off to use a PRNG. This non-atomic RMW
- * sequence has in fact positive effect, since interrupts that randomly skew
- * PRNG at unpredictable points do only good.
- */
-u8 random_tag(void)
-{
-       u32 state = this_cpu_read(prng_state);
-
-       state = 1664525 * state + 1013904223;
-       this_cpu_write(prng_state, state);
-
-       return (u8)(state % (KASAN_TAG_MAX + 1));
-}
-
-void *kasan_reset_tag(const void *addr)
-{
-       return reset_tag(addr);
-}
-
-bool check_memory_region(unsigned long addr, size_t size, bool write,
-                               unsigned long ret_ip)
-{
-       u8 tag;
-       u8 *shadow_first, *shadow_last, *shadow;
-       void *untagged_addr;
-
-       if (unlikely(size == 0))
-               return true;
-
-       if (unlikely(addr + size < addr))
-               return !kasan_report(addr, size, write, ret_ip);
-
-       tag = get_tag((const void *)addr);
-
-       /*
-        * Ignore accesses for pointers tagged with 0xff (native kernel
-        * pointer tag) to suppress false positives caused by kmap.
-        *
-        * Some kernel code was written to account for archs that don't keep
-        * high memory mapped all the time, but rather map and unmap particular
-        * pages when needed. Instead of storing a pointer to the kernel memory,
-        * this code saves the address of the page structure and offset within
-        * that page for later use. Those pages are then mapped and unmapped
-        * with kmap/kunmap when necessary and virt_to_page is used to get the
-        * virtual address of the page. For arm64 (that keeps the high memory
-        * mapped all the time), kmap is turned into a page_address call.
-
-        * The issue is that with use of the page_address + virt_to_page
-        * sequence the top byte value of the original pointer gets lost (gets
-        * set to KASAN_TAG_KERNEL (0xFF)).
-        */
-       if (tag == KASAN_TAG_KERNEL)
-               return true;
-
-       untagged_addr = reset_tag((const void *)addr);
-       if (unlikely(untagged_addr <
-                       kasan_shadow_to_mem((void *)KASAN_SHADOW_START))) {
-               return !kasan_report(addr, size, write, ret_ip);
-       }
-       shadow_first = kasan_mem_to_shadow(untagged_addr);
-       shadow_last = kasan_mem_to_shadow(untagged_addr + size - 1);
-       for (shadow = shadow_first; shadow <= shadow_last; shadow++) {
-               if (*shadow != tag) {
-                       return !kasan_report(addr, size, write, ret_ip);
-               }
-       }
-
-       return true;
-}
-
-#define DEFINE_HWASAN_LOAD_STORE(size)                                 \
-       void __hwasan_load##size##_noabort(unsigned long addr)          \
-       {                                                               \
-               check_memory_region(addr, size, false, _RET_IP_);       \
-       }                                                               \
-       EXPORT_SYMBOL(__hwasan_load##size##_noabort);                   \
-       void __hwasan_store##size##_noabort(unsigned long addr)         \
-       {                                                               \
-               check_memory_region(addr, size, true, _RET_IP_);        \
-       }                                                               \
-       EXPORT_SYMBOL(__hwasan_store##size##_noabort)
-
-DEFINE_HWASAN_LOAD_STORE(1);
-DEFINE_HWASAN_LOAD_STORE(2);
-DEFINE_HWASAN_LOAD_STORE(4);
-DEFINE_HWASAN_LOAD_STORE(8);
-DEFINE_HWASAN_LOAD_STORE(16);
-
-void __hwasan_loadN_noabort(unsigned long addr, unsigned long size)
-{
-       check_memory_region(addr, size, false, _RET_IP_);
-}
-EXPORT_SYMBOL(__hwasan_loadN_noabort);
-
-void __hwasan_storeN_noabort(unsigned long addr, unsigned long size)
-{
-       check_memory_region(addr, size, true, _RET_IP_);
-}
-EXPORT_SYMBOL(__hwasan_storeN_noabort);
-
-void __hwasan_tag_memory(unsigned long addr, u8 tag, unsigned long size)
-{
-       poison_range((void *)addr, size, tag);
-}
-EXPORT_SYMBOL(__hwasan_tag_memory);
-
-void kasan_set_free_info(struct kmem_cache *cache,
-                               void *object, u8 tag)
-{
-       struct kasan_alloc_meta *alloc_meta;
-       u8 idx = 0;
-
-       alloc_meta = get_alloc_info(cache, object);
-
-#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY
-       idx = alloc_meta->free_track_idx;
-       alloc_meta->free_pointer_tag[idx] = tag;
-       alloc_meta->free_track_idx = (idx + 1) % KASAN_NR_FREE_STACKS;
-#endif
-
-       kasan_set_track(&alloc_meta->free_track[idx], GFP_NOWAIT);
-}
-
-struct kasan_track *kasan_get_free_track(struct kmem_cache *cache,
-                               void *object, u8 tag)
-{
-       struct kasan_alloc_meta *alloc_meta;
-       int i = 0;
-
-       alloc_meta = get_alloc_info(cache, object);
-
-#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY
-       for (i = 0; i < KASAN_NR_FREE_STACKS; i++) {
-               if (alloc_meta->free_pointer_tag[i] == tag)
-                       break;
-       }
-       if (i == KASAN_NR_FREE_STACKS)
-               i = alloc_meta->free_track_idx;
-#endif
-
-       return &alloc_meta->free_track[i];
-}
diff --git a/mm/kasan/tags_report.c b/mm/kasan/tags_report.c
deleted file mode 100644 (file)
index c87d5a3..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * This file contains tag-based KASAN specific error reporting code.
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
- *
- * Some code borrowed from https://github.com/xairy/kasan-prototype by
- *        Andrey Konovalov <andreyknvl@gmail.com>
- */
-
-#include <linux/bitops.h>
-#include <linux/ftrace.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/printk.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/stackdepot.h>
-#include <linux/stacktrace.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/kasan.h>
-#include <linux/module.h>
-
-#include <asm/sections.h>
-
-#include "kasan.h"
-#include "../slab.h"
-
-const char *get_bug_type(struct kasan_access_info *info)
-{
-#ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY
-       struct kasan_alloc_meta *alloc_meta;
-       struct kmem_cache *cache;
-       struct page *page;
-       const void *addr;
-       void *object;
-       u8 tag;
-       int i;
-
-       tag = get_tag(info->access_addr);
-       addr = reset_tag(info->access_addr);
-       page = kasan_addr_to_page(addr);
-       if (page && PageSlab(page)) {
-               cache = page->slab_cache;
-               object = nearest_obj(cache, page, (void *)addr);
-               alloc_meta = get_alloc_info(cache, object);
-
-               for (i = 0; i < KASAN_NR_FREE_STACKS; i++)
-                       if (alloc_meta->free_pointer_tag[i] == tag)
-                               return "use-after-free";
-               return "out-of-bounds";
-       }
-
-#endif
-       /*
-        * If access_size is a negative number, then it has reason to be
-        * defined as out-of-bounds bug type.
-        *
-        * Casting negative numbers to size_t would indeed turn up as
-        * a large size_t and its value will be larger than ULONG_MAX/2,
-        * so that this can qualify as out-of-bounds.
-        */
-       if (info->access_addr + info->access_size < info->access_addr)
-               return "out-of-bounds";
-
-       return "invalid-access";
-}
-
-void *find_first_bad_addr(void *addr, size_t size)
-{
-       u8 tag = get_tag(addr);
-       void *p = reset_tag(addr);
-       void *end = p + size;
-
-       while (p < end && tag == *(u8 *)kasan_mem_to_shadow(p))
-               p += KASAN_GRANULE_SIZE;
-       return p;
-}
-
-void print_tags(u8 addr_tag, const void *addr)
-{
-       u8 *shadow = (u8 *)kasan_mem_to_shadow(addr);
-
-       pr_err("Pointer tag: [%02x], memory tag: [%02x]\n", addr_tag, *shadow);
-}