mm/kasan: prevent deadlock in kasan reporting
[firefly-linux-kernel-4.4.55.git] / mm / kasan / report.c
index e07c94fbd0ac5a141ecf95ab7d39d046fea13e67..7833f074ede854966a635e709bfd62c9ccbe0650 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/kasan.h>
+#include <linux/module.h>
 
 #include <asm/sections.h>
 
@@ -85,9 +86,11 @@ static void print_error_description(struct kasan_access_info *info)
 
 static inline bool kernel_or_module_addr(const void *addr)
 {
-       return (addr >= (void *)_stext && addr < (void *)_end)
-               || (addr >= (void *)MODULES_VADDR
-                       && addr < (void *)MODULES_END);
+       if (addr >= (void *)_stext && addr < (void *)_end)
+               return true;
+       if (is_module_address((unsigned long)addr))
+               return true;
+       return false;
 }
 
 static inline bool init_task_stack_addr(const void *addr)
@@ -161,15 +164,19 @@ static void print_shadow_for_address(const void *addr)
        for (i = -SHADOW_ROWS_AROUND_ADDR; i <= SHADOW_ROWS_AROUND_ADDR; i++) {
                const void *kaddr = kasan_shadow_to_mem(shadow_row);
                char buffer[4 + (BITS_PER_LONG/8)*2];
+               char shadow_buf[SHADOW_BYTES_PER_ROW];
 
                snprintf(buffer, sizeof(buffer),
                        (i == 0) ? ">%p: " : " %p: ", kaddr);
-
-               kasan_disable_current();
+               /*
+                * We should not pass a shadow pointer to generic
+                * function, because generic functions may try to
+                * access kasan mapping for the passed address.
+                */
+               memcpy(shadow_buf, shadow_row, SHADOW_BYTES_PER_ROW);
                print_hex_dump(KERN_ERR, buffer,
                        DUMP_PREFIX_NONE, SHADOW_BYTES_PER_ROW, 1,
-                       shadow_row, SHADOW_BYTES_PER_ROW, 0);
-               kasan_enable_current();
+                       shadow_buf, SHADOW_BYTES_PER_ROW, 0);
 
                if (row_is_guilty(shadow_row, shadow))
                        pr_err("%*c\n",
@@ -186,6 +193,10 @@ void kasan_report_error(struct kasan_access_info *info)
 {
        unsigned long flags;
 
+       /*
+        * Make sure we don't end up in loop.
+        */
+       kasan_disable_current();
        spin_lock_irqsave(&report_lock, flags);
        pr_err("================================="
                "=================================\n");
@@ -195,12 +206,17 @@ void kasan_report_error(struct kasan_access_info *info)
        pr_err("================================="
                "=================================\n");
        spin_unlock_irqrestore(&report_lock, flags);
+       kasan_enable_current();
 }
 
 void kasan_report_user_access(struct kasan_access_info *info)
 {
        unsigned long flags;
 
+       /*
+        * Make sure we don't end up in loop.
+        */
+       kasan_disable_current();
        spin_lock_irqsave(&report_lock, flags);
        pr_err("================================="
                "=================================\n");
@@ -213,6 +229,7 @@ void kasan_report_user_access(struct kasan_access_info *info)
        pr_err("================================="
                "=================================\n");
        spin_unlock_irqrestore(&report_lock, flags);
+       kasan_enable_current();
 }
 
 void kasan_report(unsigned long addr, size_t size,
@@ -220,7 +237,7 @@ void kasan_report(unsigned long addr, size_t size,
 {
        struct kasan_access_info info;
 
-       if (likely(!kasan_enabled()))
+       if (likely(!kasan_report_enabled()))
                return;
 
        info.access_addr = (void *)addr;