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