kasan: support use-after-scope detection
authorDmitry Vyukov <dvyukov@google.com>
Wed, 30 Nov 2016 23:54:16 +0000 (15:54 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 1 Dec 2016 00:32:52 +0000 (16:32 -0800)
Gcc revision 241896 implements use-after-scope detection.  Will be
available in gcc 7.  Support it in KASAN.

Gcc emits 2 new callbacks to poison/unpoison large stack objects when
they go in/out of scope.  Implement the callbacks and add a test.

[dvyukov@google.com: v3]
Link: http://lkml.kernel.org/r/1479998292-144502-1-git-send-email-dvyukov@google.com
Link: http://lkml.kernel.org/r/1479226045-145148-1-git-send-email-dvyukov@google.com
Signed-off-by: Dmitry Vyukov <dvyukov@google.com>
Acked-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Alexander Potapenko <glider@google.com>
Cc: <stable@vger.kernel.org> [4.0+]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
lib/test_kasan.c
mm/kasan/kasan.c
mm/kasan/kasan.h
mm/kasan/report.c

index 5e51872b3fc163af2fe82e6d7010b4aba08b612a..fbdf87920093b9b1dbd94e4b370a24e43d6bb8f7 100644 (file)
 #include <linux/uaccess.h>
 #include <linux/module.h>
 
+/*
+ * Note: test functions are marked noinline so that their names appear in
+ * reports.
+ */
+
 static noinline void __init kmalloc_oob_right(void)
 {
        char *ptr;
@@ -411,6 +416,29 @@ static noinline void __init copy_user_test(void)
        kfree(kmem);
 }
 
+static noinline void __init use_after_scope_test(void)
+{
+       volatile char *volatile p;
+
+       pr_info("use-after-scope on int\n");
+       {
+               int local = 0;
+
+               p = (char *)&local;
+       }
+       p[0] = 1;
+       p[3] = 1;
+
+       pr_info("use-after-scope on array\n");
+       {
+               char local[1024] = {0};
+
+               p = local;
+       }
+       p[0] = 1;
+       p[1023] = 1;
+}
+
 static int __init kmalloc_tests_init(void)
 {
        kmalloc_oob_right();
@@ -436,6 +464,7 @@ static int __init kmalloc_tests_init(void)
        kasan_global_oob();
        ksize_unpoisons_memory();
        copy_user_test();
+       use_after_scope_test();
        return -EAGAIN;
 }
 
index 70c009741aab705c6bb344df1f1851d9582bc7a7..0e9505f66ec133bd401d6ec9208d1a6f17b95fb7 100644 (file)
@@ -764,6 +764,25 @@ EXPORT_SYMBOL(__asan_storeN_noabort);
 void __asan_handle_no_return(void) {}
 EXPORT_SYMBOL(__asan_handle_no_return);
 
+/* Emitted by compiler to poison large objects when they go out of scope. */
+void __asan_poison_stack_memory(const void *addr, size_t size)
+{
+       /*
+        * Addr is KASAN_SHADOW_SCALE_SIZE-aligned and the object is surrounded
+        * by redzones, so we simply round up size to simplify logic.
+        */
+       kasan_poison_shadow(addr, round_up(size, KASAN_SHADOW_SCALE_SIZE),
+                           KASAN_USE_AFTER_SCOPE);
+}
+EXPORT_SYMBOL(__asan_poison_stack_memory);
+
+/* Emitted by compiler to unpoison large objects when they go into scope. */
+void __asan_unpoison_stack_memory(const void *addr, size_t size)
+{
+       kasan_unpoison_shadow(addr, size);
+}
+EXPORT_SYMBOL(__asan_unpoison_stack_memory);
+
 #ifdef CONFIG_MEMORY_HOTPLUG
 static int kasan_mem_notifier(struct notifier_block *nb,
                        unsigned long action, void *data)
index 03f4545b103d70706ae2b81f0a373416ec126967..1c260e6b3b3c6a1f26fc1e13a0fdb39099bbbf68 100644 (file)
@@ -21,6 +21,7 @@
 #define KASAN_STACK_MID         0xF2
 #define KASAN_STACK_RIGHT       0xF3
 #define KASAN_STACK_PARTIAL     0xF4
+#define KASAN_USE_AFTER_SCOPE   0xF8
 
 /* Don't break randconfig/all*config builds */
 #ifndef KASAN_ABI_VERSION
index 24c1211fe9d5e16afa715fb0b69f4aee96424224..073325aedc68542a3b05f3859d89a9872aef815f 100644 (file)
@@ -90,6 +90,9 @@ static void print_error_description(struct kasan_access_info *info)
        case KASAN_KMALLOC_FREE:
                bug_type = "use-after-free";
                break;
+       case KASAN_USE_AFTER_SCOPE:
+               bug_type = "use-after-scope";
+               break;
        }
 
        pr_err("BUG: KASAN: %s in %pS at addr %p\n",