diff options
| -rw-r--r-- | mm/kasan/common.c | 63 |
1 files changed, 43 insertions, 20 deletions
diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 44390392d4c9..73c9cbfdedf4 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c | |||
| @@ -347,28 +347,43 @@ void kasan_poison_object_data(struct kmem_cache *cache, void *object) | |||
| 347 | } | 347 | } |
| 348 | 348 | ||
| 349 | /* | 349 | /* |
| 350 | * Since it's desirable to only call object contructors once during slab | 350 | * This function assigns a tag to an object considering the following: |
| 351 | * allocation, we preassign tags to all such objects. Also preassign tags for | 351 | * 1. A cache might have a constructor, which might save a pointer to a slab |
| 352 | * SLAB_TYPESAFE_BY_RCU slabs to avoid use-after-free reports. | 352 | * object somewhere (e.g. in the object itself). We preassign a tag for |
| 353 | * For SLAB allocator we can't preassign tags randomly since the freelist is | 353 | * each object in caches with constructors during slab creation and reuse |
| 354 | * stored as an array of indexes instead of a linked list. Assign tags based | 354 | * the same tag each time a particular object is allocated. |
| 355 | * on objects indexes, so that objects that are next to each other get | 355 | * 2. A cache might be SLAB_TYPESAFE_BY_RCU, which means objects can be |
| 356 | * different tags. | 356 | * accessed after being freed. We preassign tags for objects in these |
| 357 | * After a tag is assigned, the object always gets allocated with the same tag. | 357 | * caches as well. |
| 358 | * The reason is that we can't change tags for objects with constructors on | 358 | * 3. For SLAB allocator we can't preassign tags randomly since the freelist |
| 359 | * reallocation (even for non-SLAB_TYPESAFE_BY_RCU), because the constructor | 359 | * is stored as an array of indexes instead of a linked list. Assign tags |
| 360 | * code can save the pointer to the object somewhere (e.g. in the object | 360 | * based on objects indexes, so that objects that are next to each other |
| 361 | * itself). Then if we retag it, the old saved pointer will become invalid. | 361 | * get different tags. |
| 362 | */ | 362 | */ |
| 363 | static u8 assign_tag(struct kmem_cache *cache, const void *object, bool new) | 363 | static u8 assign_tag(struct kmem_cache *cache, const void *object, |
| 364 | bool init, bool krealloc) | ||
| 364 | { | 365 | { |
| 366 | /* Reuse the same tag for krealloc'ed objects. */ | ||
| 367 | if (krealloc) | ||
| 368 | return get_tag(object); | ||
| 369 | |||
| 370 | /* | ||
| 371 | * If the cache neither has a constructor nor has SLAB_TYPESAFE_BY_RCU | ||
| 372 | * set, assign a tag when the object is being allocated (init == false). | ||
| 373 | */ | ||
| 365 | if (!cache->ctor && !(cache->flags & SLAB_TYPESAFE_BY_RCU)) | 374 | if (!cache->ctor && !(cache->flags & SLAB_TYPESAFE_BY_RCU)) |
| 366 | return new ? KASAN_TAG_KERNEL : random_tag(); | 375 | return init ? KASAN_TAG_KERNEL : random_tag(); |
| 367 | 376 | ||
| 377 | /* For caches that either have a constructor or SLAB_TYPESAFE_BY_RCU: */ | ||
| 368 | #ifdef CONFIG_SLAB | 378 | #ifdef CONFIG_SLAB |
| 379 | /* For SLAB assign tags based on the object index in the freelist. */ | ||
| 369 | return (u8)obj_to_index(cache, virt_to_page(object), (void *)object); | 380 | return (u8)obj_to_index(cache, virt_to_page(object), (void *)object); |
| 370 | #else | 381 | #else |
| 371 | return new ? random_tag() : get_tag(object); | 382 | /* |
| 383 | * For SLUB assign a random tag during slab creation, otherwise reuse | ||
| 384 | * the already assigned tag. | ||
| 385 | */ | ||
| 386 | return init ? random_tag() : get_tag(object); | ||
| 372 | #endif | 387 | #endif |
| 373 | } | 388 | } |
| 374 | 389 | ||
| @@ -384,7 +399,8 @@ void * __must_check kasan_init_slab_obj(struct kmem_cache *cache, | |||
| 384 | __memset(alloc_info, 0, sizeof(*alloc_info)); | 399 | __memset(alloc_info, 0, sizeof(*alloc_info)); |
| 385 | 400 | ||
| 386 | if (IS_ENABLED(CONFIG_KASAN_SW_TAGS)) | 401 | if (IS_ENABLED(CONFIG_KASAN_SW_TAGS)) |
| 387 | object = set_tag(object, assign_tag(cache, object, true)); | 402 | object = set_tag(object, |
| 403 | assign_tag(cache, object, true, false)); | ||
| 388 | 404 | ||
| 389 | return (void *)object; | 405 | return (void *)object; |
| 390 | } | 406 | } |
| @@ -450,8 +466,8 @@ bool kasan_slab_free(struct kmem_cache *cache, void *object, unsigned long ip) | |||
| 450 | return __kasan_slab_free(cache, object, ip, true); | 466 | return __kasan_slab_free(cache, object, ip, true); |
| 451 | } | 467 | } |
| 452 | 468 | ||
| 453 | void * __must_check kasan_kmalloc(struct kmem_cache *cache, const void *object, | 469 | static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object, |
| 454 | size_t size, gfp_t flags) | 470 | size_t size, gfp_t flags, bool krealloc) |
| 455 | { | 471 | { |
| 456 | unsigned long redzone_start; | 472 | unsigned long redzone_start; |
| 457 | unsigned long redzone_end; | 473 | unsigned long redzone_end; |
| @@ -469,7 +485,7 @@ void * __must_check kasan_kmalloc(struct kmem_cache *cache, const void *object, | |||
| 469 | KASAN_SHADOW_SCALE_SIZE); | 485 | KASAN_SHADOW_SCALE_SIZE); |
| 470 | 486 | ||
| 471 | if (IS_ENABLED(CONFIG_KASAN_SW_TAGS)) | 487 | if (IS_ENABLED(CONFIG_KASAN_SW_TAGS)) |
| 472 | tag = assign_tag(cache, object, false); | 488 | tag = assign_tag(cache, object, false, krealloc); |
| 473 | 489 | ||
| 474 | /* Tag is ignored in set_tag without CONFIG_KASAN_SW_TAGS */ | 490 | /* Tag is ignored in set_tag without CONFIG_KASAN_SW_TAGS */ |
| 475 | kasan_unpoison_shadow(set_tag(object, tag), size); | 491 | kasan_unpoison_shadow(set_tag(object, tag), size); |
| @@ -481,6 +497,12 @@ void * __must_check kasan_kmalloc(struct kmem_cache *cache, const void *object, | |||
| 481 | 497 | ||
| 482 | return set_tag(object, tag); | 498 | return set_tag(object, tag); |
| 483 | } | 499 | } |
| 500 | |||
| 501 | void * __must_check kasan_kmalloc(struct kmem_cache *cache, const void *object, | ||
| 502 | size_t size, gfp_t flags) | ||
| 503 | { | ||
| 504 | return __kasan_kmalloc(cache, object, size, flags, false); | ||
| 505 | } | ||
| 484 | EXPORT_SYMBOL(kasan_kmalloc); | 506 | EXPORT_SYMBOL(kasan_kmalloc); |
| 485 | 507 | ||
| 486 | void * __must_check kasan_kmalloc_large(const void *ptr, size_t size, | 508 | void * __must_check kasan_kmalloc_large(const void *ptr, size_t size, |
| @@ -520,7 +542,8 @@ void * __must_check kasan_krealloc(const void *object, size_t size, gfp_t flags) | |||
| 520 | if (unlikely(!PageSlab(page))) | 542 | if (unlikely(!PageSlab(page))) |
| 521 | return kasan_kmalloc_large(object, size, flags); | 543 | return kasan_kmalloc_large(object, size, flags); |
| 522 | else | 544 | else |
| 523 | return kasan_kmalloc(page->slab_cache, object, size, flags); | 545 | return __kasan_kmalloc(page->slab_cache, object, size, |
| 546 | flags, true); | ||
| 524 | } | 547 | } |
| 525 | 548 | ||
| 526 | void kasan_poison_kfree(void *ptr, unsigned long ip) | 549 | void kasan_poison_kfree(void *ptr, unsigned long ip) |
