This is a preparatory commit for the upcoming addition of a new hardware
tag-based (MTE-based) KASAN mode.

For software KASAN modes the check is based on the value in the shadow
memory. Hardware tag-based KASAN won't be using shadow, so hide the
implementation of the check in check_invalid_free().

No functional changes for software modes.

Signed-off-by: Andrey Konovalov <[email protected]>
---
 mm/kasan/common.c  | 19 +------------------
 mm/kasan/generic.c |  7 +++++++
 mm/kasan/kasan.h   |  2 ++
 mm/kasan/tags.c    | 12 ++++++++++++
 4 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/mm/kasan/common.c b/mm/kasan/common.c
index 43a927e70067..a2321d35390e 100644
--- a/mm/kasan/common.c
+++ b/mm/kasan/common.c
@@ -277,25 +277,9 @@ void * __must_check kasan_init_slab_obj(struct kmem_cache 
*cache,
        return (void *)object;
 }
 
-static inline bool shadow_invalid(u8 tag, s8 shadow_byte)
-{
-       if (IS_ENABLED(CONFIG_KASAN_GENERIC))
-               return shadow_byte < 0 ||
-                       shadow_byte >= KASAN_GRANULE_SIZE;
-
-       /* else CONFIG_KASAN_SW_TAGS: */
-       if ((u8)shadow_byte == KASAN_TAG_INVALID)
-               return true;
-       if ((tag != KASAN_TAG_KERNEL) && (tag != (u8)shadow_byte))
-               return true;
-
-       return false;
-}
-
 static bool __kasan_slab_free(struct kmem_cache *cache, void *object,
                              unsigned long ip, bool quarantine)
 {
-       s8 shadow_byte;
        u8 tag;
        void *tagged_object;
        unsigned long rounded_up_size;
@@ -314,8 +298,7 @@ static bool __kasan_slab_free(struct kmem_cache *cache, 
void *object,
        if (unlikely(cache->flags & SLAB_TYPESAFE_BY_RCU))
                return false;
 
-       shadow_byte = READ_ONCE(*(s8 *)kasan_mem_to_shadow(object));
-       if (shadow_invalid(tag, shadow_byte)) {
+       if (check_invalid_free(tagged_object)) {
                kasan_report_invalid_free(tagged_object, ip);
                return true;
        }
diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c
index f6d68aa9872f..73f4d786ad5d 100644
--- a/mm/kasan/generic.c
+++ b/mm/kasan/generic.c
@@ -192,6 +192,13 @@ bool check_memory_region(unsigned long addr, size_t size, 
bool write,
        return check_memory_region_inline(addr, size, write, ret_ip);
 }
 
+bool check_invalid_free(void *addr)
+{
+       s8 shadow_byte = READ_ONCE(*(s8 *)kasan_mem_to_shadow(addr));
+
+       return shadow_byte < 0 || shadow_byte >= KASAN_GRANULE_SIZE;
+}
+
 void kasan_cache_shrink(struct kmem_cache *cache)
 {
        quarantine_remove_cache(cache);
diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h
index c31e2c739301..cf6a135860f2 100644
--- a/mm/kasan/kasan.h
+++ b/mm/kasan/kasan.h
@@ -163,6 +163,8 @@ void kasan_poison_memory(const void *address, size_t size, 
u8 value);
 bool check_memory_region(unsigned long addr, size_t size, bool write,
                                unsigned long ret_ip);
 
+bool check_invalid_free(void *addr);
+
 void *find_first_bad_addr(void *addr, size_t size);
 const char *get_bug_type(struct kasan_access_info *info);
 
diff --git a/mm/kasan/tags.c b/mm/kasan/tags.c
index 4d5a1fe8251f..feb42c1763b8 100644
--- a/mm/kasan/tags.c
+++ b/mm/kasan/tags.c
@@ -126,6 +126,18 @@ bool check_memory_region(unsigned long addr, size_t size, 
bool write,
        return true;
 }
 
+bool check_invalid_free(void *addr)
+{
+       u8 tag = get_tag(addr);
+       u8 shadow_byte = READ_ONCE(*(u8 *)kasan_mem_to_shadow(reset_tag(addr)));
+
+       if (shadow_byte == KASAN_TAG_INVALID)
+               return true;
+       if (tag != KASAN_TAG_KERNEL && tag != shadow_byte)
+               return true;
+       return false;
+}
+
 #define DEFINE_HWASAN_LOAD_STORE(size)                                 \
        void __hwasan_load##size##_noabort(unsigned long addr)          \
        {                                                               \
-- 
2.28.0.220.ged08abb693-goog

Reply via email to