at v4.9 9.3 kB view raw
1/* 2 * 3 * Copyright (c) 2014 Samsung Electronics Co., Ltd. 4 * Author: Andrey Ryabinin <a.ryabinin@samsung.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 */ 11 12#define pr_fmt(fmt) "kasan test: %s " fmt, __func__ 13 14#include <linux/kernel.h> 15#include <linux/mman.h> 16#include <linux/mm.h> 17#include <linux/printk.h> 18#include <linux/slab.h> 19#include <linux/string.h> 20#include <linux/uaccess.h> 21#include <linux/module.h> 22 23/* 24 * Note: test functions are marked noinline so that their names appear in 25 * reports. 26 */ 27 28static noinline void __init kmalloc_oob_right(void) 29{ 30 char *ptr; 31 size_t size = 123; 32 33 pr_info("out-of-bounds to right\n"); 34 ptr = kmalloc(size, GFP_KERNEL); 35 if (!ptr) { 36 pr_err("Allocation failed\n"); 37 return; 38 } 39 40 ptr[size] = 'x'; 41 kfree(ptr); 42} 43 44static noinline void __init kmalloc_oob_left(void) 45{ 46 char *ptr; 47 size_t size = 15; 48 49 pr_info("out-of-bounds to left\n"); 50 ptr = kmalloc(size, GFP_KERNEL); 51 if (!ptr) { 52 pr_err("Allocation failed\n"); 53 return; 54 } 55 56 *ptr = *(ptr - 1); 57 kfree(ptr); 58} 59 60static noinline void __init kmalloc_node_oob_right(void) 61{ 62 char *ptr; 63 size_t size = 4096; 64 65 pr_info("kmalloc_node(): out-of-bounds to right\n"); 66 ptr = kmalloc_node(size, GFP_KERNEL, 0); 67 if (!ptr) { 68 pr_err("Allocation failed\n"); 69 return; 70 } 71 72 ptr[size] = 0; 73 kfree(ptr); 74} 75 76#ifdef CONFIG_SLUB 77static noinline void __init kmalloc_pagealloc_oob_right(void) 78{ 79 char *ptr; 80 size_t size = KMALLOC_MAX_CACHE_SIZE + 10; 81 82 /* Allocate a chunk that does not fit into a SLUB cache to trigger 83 * the page allocator fallback. 84 */ 85 pr_info("kmalloc pagealloc allocation: out-of-bounds to right\n"); 86 ptr = kmalloc(size, GFP_KERNEL); 87 if (!ptr) { 88 pr_err("Allocation failed\n"); 89 return; 90 } 91 92 ptr[size] = 0; 93 kfree(ptr); 94} 95#endif 96 97static noinline void __init kmalloc_large_oob_right(void) 98{ 99 char *ptr; 100 size_t size = KMALLOC_MAX_CACHE_SIZE - 256; 101 /* Allocate a chunk that is large enough, but still fits into a slab 102 * and does not trigger the page allocator fallback in SLUB. 103 */ 104 pr_info("kmalloc large allocation: out-of-bounds to right\n"); 105 ptr = kmalloc(size, GFP_KERNEL); 106 if (!ptr) { 107 pr_err("Allocation failed\n"); 108 return; 109 } 110 111 ptr[size] = 0; 112 kfree(ptr); 113} 114 115static noinline void __init kmalloc_oob_krealloc_more(void) 116{ 117 char *ptr1, *ptr2; 118 size_t size1 = 17; 119 size_t size2 = 19; 120 121 pr_info("out-of-bounds after krealloc more\n"); 122 ptr1 = kmalloc(size1, GFP_KERNEL); 123 ptr2 = krealloc(ptr1, size2, GFP_KERNEL); 124 if (!ptr1 || !ptr2) { 125 pr_err("Allocation failed\n"); 126 kfree(ptr1); 127 return; 128 } 129 130 ptr2[size2] = 'x'; 131 kfree(ptr2); 132} 133 134static noinline void __init kmalloc_oob_krealloc_less(void) 135{ 136 char *ptr1, *ptr2; 137 size_t size1 = 17; 138 size_t size2 = 15; 139 140 pr_info("out-of-bounds after krealloc less\n"); 141 ptr1 = kmalloc(size1, GFP_KERNEL); 142 ptr2 = krealloc(ptr1, size2, GFP_KERNEL); 143 if (!ptr1 || !ptr2) { 144 pr_err("Allocation failed\n"); 145 kfree(ptr1); 146 return; 147 } 148 ptr2[size2] = 'x'; 149 kfree(ptr2); 150} 151 152static noinline void __init kmalloc_oob_16(void) 153{ 154 struct { 155 u64 words[2]; 156 } *ptr1, *ptr2; 157 158 pr_info("kmalloc out-of-bounds for 16-bytes access\n"); 159 ptr1 = kmalloc(sizeof(*ptr1) - 3, GFP_KERNEL); 160 ptr2 = kmalloc(sizeof(*ptr2), GFP_KERNEL); 161 if (!ptr1 || !ptr2) { 162 pr_err("Allocation failed\n"); 163 kfree(ptr1); 164 kfree(ptr2); 165 return; 166 } 167 *ptr1 = *ptr2; 168 kfree(ptr1); 169 kfree(ptr2); 170} 171 172static noinline void __init kmalloc_oob_memset_2(void) 173{ 174 char *ptr; 175 size_t size = 8; 176 177 pr_info("out-of-bounds in memset2\n"); 178 ptr = kmalloc(size, GFP_KERNEL); 179 if (!ptr) { 180 pr_err("Allocation failed\n"); 181 return; 182 } 183 184 memset(ptr+7, 0, 2); 185 kfree(ptr); 186} 187 188static noinline void __init kmalloc_oob_memset_4(void) 189{ 190 char *ptr; 191 size_t size = 8; 192 193 pr_info("out-of-bounds in memset4\n"); 194 ptr = kmalloc(size, GFP_KERNEL); 195 if (!ptr) { 196 pr_err("Allocation failed\n"); 197 return; 198 } 199 200 memset(ptr+5, 0, 4); 201 kfree(ptr); 202} 203 204 205static noinline void __init kmalloc_oob_memset_8(void) 206{ 207 char *ptr; 208 size_t size = 8; 209 210 pr_info("out-of-bounds in memset8\n"); 211 ptr = kmalloc(size, GFP_KERNEL); 212 if (!ptr) { 213 pr_err("Allocation failed\n"); 214 return; 215 } 216 217 memset(ptr+1, 0, 8); 218 kfree(ptr); 219} 220 221static noinline void __init kmalloc_oob_memset_16(void) 222{ 223 char *ptr; 224 size_t size = 16; 225 226 pr_info("out-of-bounds in memset16\n"); 227 ptr = kmalloc(size, GFP_KERNEL); 228 if (!ptr) { 229 pr_err("Allocation failed\n"); 230 return; 231 } 232 233 memset(ptr+1, 0, 16); 234 kfree(ptr); 235} 236 237static noinline void __init kmalloc_oob_in_memset(void) 238{ 239 char *ptr; 240 size_t size = 666; 241 242 pr_info("out-of-bounds in memset\n"); 243 ptr = kmalloc(size, GFP_KERNEL); 244 if (!ptr) { 245 pr_err("Allocation failed\n"); 246 return; 247 } 248 249 memset(ptr, 0, size+5); 250 kfree(ptr); 251} 252 253static noinline void __init kmalloc_uaf(void) 254{ 255 char *ptr; 256 size_t size = 10; 257 258 pr_info("use-after-free\n"); 259 ptr = kmalloc(size, GFP_KERNEL); 260 if (!ptr) { 261 pr_err("Allocation failed\n"); 262 return; 263 } 264 265 kfree(ptr); 266 *(ptr + 8) = 'x'; 267} 268 269static noinline void __init kmalloc_uaf_memset(void) 270{ 271 char *ptr; 272 size_t size = 33; 273 274 pr_info("use-after-free in memset\n"); 275 ptr = kmalloc(size, GFP_KERNEL); 276 if (!ptr) { 277 pr_err("Allocation failed\n"); 278 return; 279 } 280 281 kfree(ptr); 282 memset(ptr, 0, size); 283} 284 285static noinline void __init kmalloc_uaf2(void) 286{ 287 char *ptr1, *ptr2; 288 size_t size = 43; 289 290 pr_info("use-after-free after another kmalloc\n"); 291 ptr1 = kmalloc(size, GFP_KERNEL); 292 if (!ptr1) { 293 pr_err("Allocation failed\n"); 294 return; 295 } 296 297 kfree(ptr1); 298 ptr2 = kmalloc(size, GFP_KERNEL); 299 if (!ptr2) { 300 pr_err("Allocation failed\n"); 301 return; 302 } 303 304 ptr1[40] = 'x'; 305 if (ptr1 == ptr2) 306 pr_err("Could not detect use-after-free: ptr1 == ptr2\n"); 307 kfree(ptr2); 308} 309 310static noinline void __init kmem_cache_oob(void) 311{ 312 char *p; 313 size_t size = 200; 314 struct kmem_cache *cache = kmem_cache_create("test_cache", 315 size, 0, 316 0, NULL); 317 if (!cache) { 318 pr_err("Cache allocation failed\n"); 319 return; 320 } 321 pr_info("out-of-bounds in kmem_cache_alloc\n"); 322 p = kmem_cache_alloc(cache, GFP_KERNEL); 323 if (!p) { 324 pr_err("Allocation failed\n"); 325 kmem_cache_destroy(cache); 326 return; 327 } 328 329 *p = p[size]; 330 kmem_cache_free(cache, p); 331 kmem_cache_destroy(cache); 332} 333 334static char global_array[10]; 335 336static noinline void __init kasan_global_oob(void) 337{ 338 volatile int i = 3; 339 char *p = &global_array[ARRAY_SIZE(global_array) + i]; 340 341 pr_info("out-of-bounds global variable\n"); 342 *(volatile char *)p; 343} 344 345static noinline void __init kasan_stack_oob(void) 346{ 347 char stack_array[10]; 348 volatile int i = 0; 349 char *p = &stack_array[ARRAY_SIZE(stack_array) + i]; 350 351 pr_info("out-of-bounds on stack\n"); 352 *(volatile char *)p; 353} 354 355static noinline void __init ksize_unpoisons_memory(void) 356{ 357 char *ptr; 358 size_t size = 123, real_size = size; 359 360 pr_info("ksize() unpoisons the whole allocated chunk\n"); 361 ptr = kmalloc(size, GFP_KERNEL); 362 if (!ptr) { 363 pr_err("Allocation failed\n"); 364 return; 365 } 366 real_size = ksize(ptr); 367 /* This access doesn't trigger an error. */ 368 ptr[size] = 'x'; 369 /* This one does. */ 370 ptr[real_size] = 'y'; 371 kfree(ptr); 372} 373 374static noinline void __init copy_user_test(void) 375{ 376 char *kmem; 377 char __user *usermem; 378 size_t size = 10; 379 int unused; 380 381 kmem = kmalloc(size, GFP_KERNEL); 382 if (!kmem) 383 return; 384 385 usermem = (char __user *)vm_mmap(NULL, 0, PAGE_SIZE, 386 PROT_READ | PROT_WRITE | PROT_EXEC, 387 MAP_ANONYMOUS | MAP_PRIVATE, 0); 388 if (IS_ERR(usermem)) { 389 pr_err("Failed to allocate user memory\n"); 390 kfree(kmem); 391 return; 392 } 393 394 pr_info("out-of-bounds in copy_from_user()\n"); 395 unused = copy_from_user(kmem, usermem, size + 1); 396 397 pr_info("out-of-bounds in copy_to_user()\n"); 398 unused = copy_to_user(usermem, kmem, size + 1); 399 400 pr_info("out-of-bounds in __copy_from_user()\n"); 401 unused = __copy_from_user(kmem, usermem, size + 1); 402 403 pr_info("out-of-bounds in __copy_to_user()\n"); 404 unused = __copy_to_user(usermem, kmem, size + 1); 405 406 pr_info("out-of-bounds in __copy_from_user_inatomic()\n"); 407 unused = __copy_from_user_inatomic(kmem, usermem, size + 1); 408 409 pr_info("out-of-bounds in __copy_to_user_inatomic()\n"); 410 unused = __copy_to_user_inatomic(usermem, kmem, size + 1); 411 412 pr_info("out-of-bounds in strncpy_from_user()\n"); 413 unused = strncpy_from_user(kmem, usermem, size + 1); 414 415 vm_munmap((unsigned long)usermem, PAGE_SIZE); 416 kfree(kmem); 417} 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 442static int __init kmalloc_tests_init(void) 443{ 444 kmalloc_oob_right(); 445 kmalloc_oob_left(); 446 kmalloc_node_oob_right(); 447#ifdef CONFIG_SLUB 448 kmalloc_pagealloc_oob_right(); 449#endif 450 kmalloc_large_oob_right(); 451 kmalloc_oob_krealloc_more(); 452 kmalloc_oob_krealloc_less(); 453 kmalloc_oob_16(); 454 kmalloc_oob_in_memset(); 455 kmalloc_oob_memset_2(); 456 kmalloc_oob_memset_4(); 457 kmalloc_oob_memset_8(); 458 kmalloc_oob_memset_16(); 459 kmalloc_uaf(); 460 kmalloc_uaf_memset(); 461 kmalloc_uaf2(); 462 kmem_cache_oob(); 463 kasan_stack_oob(); 464 kasan_global_oob(); 465 ksize_unpoisons_memory(); 466 copy_user_test(); 467 use_after_scope_test(); 468 return -EAGAIN; 469} 470 471module_init(kmalloc_tests_init); 472MODULE_LICENSE("GPL");