aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2016-11-30 18:54:16 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-11-30 19:32:52 -0500
commit828347f8f9a558cf1af2faa46387a26564f2ac3e (patch)
tree4acb63366cc89b3e87e85805530911300dd4ab19
parent045d599a286bc01daa3510d59272440a17b23c2e (diff)
kasan: support use-after-scope detection
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>
-rw-r--r--lib/test_kasan.c29
-rw-r--r--mm/kasan/kasan.c19
-rw-r--r--mm/kasan/kasan.h1
-rw-r--r--mm/kasan/report.c3
4 files changed, 52 insertions, 0 deletions
diff --git a/lib/test_kasan.c b/lib/test_kasan.c
index 5e51872b3fc1..fbdf87920093 100644
--- a/lib/test_kasan.c
+++ b/lib/test_kasan.c
@@ -20,6 +20,11 @@
20#include <linux/uaccess.h> 20#include <linux/uaccess.h>
21#include <linux/module.h> 21#include <linux/module.h>
22 22
23/*
24 * Note: test functions are marked noinline so that their names appear in
25 * reports.
26 */
27
23static noinline void __init kmalloc_oob_right(void) 28static noinline void __init kmalloc_oob_right(void)
24{ 29{
25 char *ptr; 30 char *ptr;
@@ -411,6 +416,29 @@ static noinline void __init copy_user_test(void)
411 kfree(kmem); 416 kfree(kmem);
412} 417}
413 418
419static noinline void __init use_after_scope_test(void)
420{
421 volatile char *volatile p;
422
423 pr_info("use-after-scope on int\n");
424 {
425 int local = 0;
426
427 p = (char *)&local;
428 }
429 p[0] = 1;
430 p[3] = 1;
431
432 pr_info("use-after-scope on array\n");
433 {
434 char local[1024] = {0};
435
436 p = local;
437 }
438 p[0] = 1;
439 p[1023] = 1;
440}
441
414static int __init kmalloc_tests_init(void) 442static int __init kmalloc_tests_init(void)
415{ 443{
416 kmalloc_oob_right(); 444 kmalloc_oob_right();
@@ -436,6 +464,7 @@ static int __init kmalloc_tests_init(void)
436 kasan_global_oob(); 464 kasan_global_oob();
437 ksize_unpoisons_memory(); 465 ksize_unpoisons_memory();
438 copy_user_test(); 466 copy_user_test();
467 use_after_scope_test();
439 return -EAGAIN; 468 return -EAGAIN;
440} 469}
441 470
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c
index 70c009741aab..0e9505f66ec1 100644
--- a/mm/kasan/kasan.c
+++ b/mm/kasan/kasan.c
@@ -764,6 +764,25 @@ EXPORT_SYMBOL(__asan_storeN_noabort);
764void __asan_handle_no_return(void) {} 764void __asan_handle_no_return(void) {}
765EXPORT_SYMBOL(__asan_handle_no_return); 765EXPORT_SYMBOL(__asan_handle_no_return);
766 766
767/* Emitted by compiler to poison large objects when they go out of scope. */
768void __asan_poison_stack_memory(const void *addr, size_t size)
769{
770 /*
771 * Addr is KASAN_SHADOW_SCALE_SIZE-aligned and the object is surrounded
772 * by redzones, so we simply round up size to simplify logic.
773 */
774 kasan_poison_shadow(addr, round_up(size, KASAN_SHADOW_SCALE_SIZE),
775 KASAN_USE_AFTER_SCOPE);
776}
777EXPORT_SYMBOL(__asan_poison_stack_memory);
778
779/* Emitted by compiler to unpoison large objects when they go into scope. */
780void __asan_unpoison_stack_memory(const void *addr, size_t size)
781{
782 kasan_unpoison_shadow(addr, size);
783}
784EXPORT_SYMBOL(__asan_unpoison_stack_memory);
785
767#ifdef CONFIG_MEMORY_HOTPLUG 786#ifdef CONFIG_MEMORY_HOTPLUG
768static int kasan_mem_notifier(struct notifier_block *nb, 787static int kasan_mem_notifier(struct notifier_block *nb,
769 unsigned long action, void *data) 788 unsigned long action, void *data)
diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h
index 03f4545b103d..1c260e6b3b3c 100644
--- a/mm/kasan/kasan.h
+++ b/mm/kasan/kasan.h
@@ -21,6 +21,7 @@
21#define KASAN_STACK_MID 0xF2 21#define KASAN_STACK_MID 0xF2
22#define KASAN_STACK_RIGHT 0xF3 22#define KASAN_STACK_RIGHT 0xF3
23#define KASAN_STACK_PARTIAL 0xF4 23#define KASAN_STACK_PARTIAL 0xF4
24#define KASAN_USE_AFTER_SCOPE 0xF8
24 25
25/* Don't break randconfig/all*config builds */ 26/* Don't break randconfig/all*config builds */
26#ifndef KASAN_ABI_VERSION 27#ifndef KASAN_ABI_VERSION
diff --git a/mm/kasan/report.c b/mm/kasan/report.c
index 24c1211fe9d5..073325aedc68 100644
--- a/mm/kasan/report.c
+++ b/mm/kasan/report.c
@@ -90,6 +90,9 @@ static void print_error_description(struct kasan_access_info *info)
90 case KASAN_KMALLOC_FREE: 90 case KASAN_KMALLOC_FREE:
91 bug_type = "use-after-free"; 91 bug_type = "use-after-free";
92 break; 92 break;
93 case KASAN_USE_AFTER_SCOPE:
94 bug_type = "use-after-scope";
95 break;
93 } 96 }
94 97
95 pr_err("BUG: KASAN: %s in %pS at addr %p\n", 98 pr_err("BUG: KASAN: %s in %pS at addr %p\n",