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>
This commit is contained in:
		
							parent
							
								
									045d599a28
								
							
						
					
					
						commit
						828347f8f9
					
				| @ -20,6 +20,11 @@ | |||||||
| #include <linux/uaccess.h> | #include <linux/uaccess.h> | ||||||
| #include <linux/module.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) | static noinline void __init kmalloc_oob_right(void) | ||||||
| { | { | ||||||
| 	char *ptr; | 	char *ptr; | ||||||
| @ -411,6 +416,29 @@ static noinline void __init copy_user_test(void) | |||||||
| 	kfree(kmem); | 	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) | static int __init kmalloc_tests_init(void) | ||||||
| { | { | ||||||
| 	kmalloc_oob_right(); | 	kmalloc_oob_right(); | ||||||
| @ -436,6 +464,7 @@ static int __init kmalloc_tests_init(void) | |||||||
| 	kasan_global_oob(); | 	kasan_global_oob(); | ||||||
| 	ksize_unpoisons_memory(); | 	ksize_unpoisons_memory(); | ||||||
| 	copy_user_test(); | 	copy_user_test(); | ||||||
|  | 	use_after_scope_test(); | ||||||
| 	return -EAGAIN; | 	return -EAGAIN; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -764,6 +764,25 @@ EXPORT_SYMBOL(__asan_storeN_noabort); | |||||||
| void __asan_handle_no_return(void) {} | void __asan_handle_no_return(void) {} | ||||||
| EXPORT_SYMBOL(__asan_handle_no_return); | 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 | #ifdef CONFIG_MEMORY_HOTPLUG | ||||||
| static int kasan_mem_notifier(struct notifier_block *nb, | static int kasan_mem_notifier(struct notifier_block *nb, | ||||||
| 			unsigned long action, void *data) | 			unsigned long action, void *data) | ||||||
|  | |||||||
| @ -21,6 +21,7 @@ | |||||||
| #define KASAN_STACK_MID         0xF2 | #define KASAN_STACK_MID         0xF2 | ||||||
| #define KASAN_STACK_RIGHT       0xF3 | #define KASAN_STACK_RIGHT       0xF3 | ||||||
| #define KASAN_STACK_PARTIAL     0xF4 | #define KASAN_STACK_PARTIAL     0xF4 | ||||||
|  | #define KASAN_USE_AFTER_SCOPE   0xF8 | ||||||
| 
 | 
 | ||||||
| /* Don't break randconfig/all*config builds */ | /* Don't break randconfig/all*config builds */ | ||||||
| #ifndef KASAN_ABI_VERSION | #ifndef KASAN_ABI_VERSION | ||||||
|  | |||||||
| @ -90,6 +90,9 @@ static void print_error_description(struct kasan_access_info *info) | |||||||
| 	case KASAN_KMALLOC_FREE: | 	case KASAN_KMALLOC_FREE: | ||||||
| 		bug_type = "use-after-free"; | 		bug_type = "use-after-free"; | ||||||
| 		break; | 		break; | ||||||
|  | 	case KASAN_USE_AFTER_SCOPE: | ||||||
|  | 		bug_type = "use-after-scope"; | ||||||
|  | 		break; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	pr_err("BUG: KASAN: %s in %pS at addr %p\n", | 	pr_err("BUG: KASAN: %s in %pS at addr %p\n", | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user