diff options
Diffstat (limited to 'mm/kasan/common.c')
| -rw-r--r-- | mm/kasan/common.c | 82 |
1 files changed, 54 insertions, 28 deletions
diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 03d5d1374ca7..09b534fbba17 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c | |||
| @@ -298,8 +298,6 @@ void kasan_cache_create(struct kmem_cache *cache, unsigned int *size, | |||
| 298 | return; | 298 | return; |
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | cache->align = round_up(cache->align, KASAN_SHADOW_SCALE_SIZE); | ||
| 302 | |||
| 303 | *flags |= SLAB_KASAN; | 301 | *flags |= SLAB_KASAN; |
| 304 | } | 302 | } |
| 305 | 303 | ||
| @@ -349,28 +347,48 @@ void kasan_poison_object_data(struct kmem_cache *cache, void *object) | |||
| 349 | } | 347 | } |
| 350 | 348 | ||
| 351 | /* | 349 | /* |
| 352 | * Since it's desirable to only call object contructors once during slab | 350 | * This function assigns a tag to an object considering the following: |
| 353 | * 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 |
| 354 | * 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 |
| 355 | * 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 |
| 356 | * 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. |
| 357 | * 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 |
| 358 | * different tags. | 356 | * accessed after being freed. We preassign tags for objects in these |
| 359 | * After a tag is assigned, the object always gets allocated with the same tag. | 357 | * caches as well. |
| 360 | * 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 |
| 361 | * 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 |
| 362 | * 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 |
| 363 | * itself). Then if we retag it, the old saved pointer will become invalid. | 361 | * get different tags. |
| 364 | */ | 362 | */ |
| 365 | 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 keep_tag) | ||
| 366 | { | 365 | { |
| 366 | /* | ||
| 367 | * 1. When an object is kmalloc()'ed, two hooks are called: | ||
| 368 | * kasan_slab_alloc() and kasan_kmalloc(). We assign the | ||
| 369 | * tag only in the first one. | ||
| 370 | * 2. We reuse the same tag for krealloc'ed objects. | ||
| 371 | */ | ||
| 372 | if (keep_tag) | ||
| 373 | return get_tag(object); | ||
| 374 | |||
| 375 | /* | ||
| 376 | * If the cache neither has a constructor nor has SLAB_TYPESAFE_BY_RCU | ||
| 377 | * set, assign a tag when the object is being allocated (init == false). | ||
| 378 | */ | ||
| 367 | if (!cache->ctor && !(cache->flags & SLAB_TYPESAFE_BY_RCU)) | 379 | if (!cache->ctor && !(cache->flags & SLAB_TYPESAFE_BY_RCU)) |
| 368 | return new ? KASAN_TAG_KERNEL : random_tag(); | 380 | return init ? KASAN_TAG_KERNEL : random_tag(); |
| 369 | 381 | ||
| 382 | /* For caches that either have a constructor or SLAB_TYPESAFE_BY_RCU: */ | ||
| 370 | #ifdef CONFIG_SLAB | 383 | #ifdef CONFIG_SLAB |
| 384 | /* For SLAB assign tags based on the object index in the freelist. */ | ||
| 371 | return (u8)obj_to_index(cache, virt_to_page(object), (void *)object); | 385 | return (u8)obj_to_index(cache, virt_to_page(object), (void *)object); |
| 372 | #else | 386 | #else |
| 373 | return new ? random_tag() : get_tag(object); | 387 | /* |
| 388 | * For SLUB assign a random tag during slab creation, otherwise reuse | ||
| 389 | * the already assigned tag. | ||
| 390 | */ | ||
| 391 | return init ? random_tag() : get_tag(object); | ||
| 374 | #endif | 392 | #endif |
| 375 | } | 393 | } |
| 376 | 394 | ||
| @@ -386,17 +404,12 @@ void * __must_check kasan_init_slab_obj(struct kmem_cache *cache, | |||
| 386 | __memset(alloc_info, 0, sizeof(*alloc_info)); | 404 | __memset(alloc_info, 0, sizeof(*alloc_info)); |
| 387 | 405 | ||
| 388 | if (IS_ENABLED(CONFIG_KASAN_SW_TAGS)) | 406 | if (IS_ENABLED(CONFIG_KASAN_SW_TAGS)) |
| 389 | object = set_tag(object, assign_tag(cache, object, true)); | 407 | object = set_tag(object, |
| 408 | assign_tag(cache, object, true, false)); | ||
| 390 | 409 | ||
| 391 | return (void *)object; | 410 | return (void *)object; |
| 392 | } | 411 | } |
| 393 | 412 | ||
| 394 | void * __must_check kasan_slab_alloc(struct kmem_cache *cache, void *object, | ||
| 395 | gfp_t flags) | ||
| 396 | { | ||
| 397 | return kasan_kmalloc(cache, object, cache->object_size, flags); | ||
| 398 | } | ||
| 399 | |||
| 400 | static inline bool shadow_invalid(u8 tag, s8 shadow_byte) | 413 | static inline bool shadow_invalid(u8 tag, s8 shadow_byte) |
| 401 | { | 414 | { |
| 402 | if (IS_ENABLED(CONFIG_KASAN_GENERIC)) | 415 | if (IS_ENABLED(CONFIG_KASAN_GENERIC)) |
| @@ -452,8 +465,8 @@ bool kasan_slab_free(struct kmem_cache *cache, void *object, unsigned long ip) | |||
| 452 | return __kasan_slab_free(cache, object, ip, true); | 465 | return __kasan_slab_free(cache, object, ip, true); |
| 453 | } | 466 | } |
| 454 | 467 | ||
| 455 | void * __must_check kasan_kmalloc(struct kmem_cache *cache, const void *object, | 468 | static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object, |
| 456 | size_t size, gfp_t flags) | 469 | size_t size, gfp_t flags, bool keep_tag) |
| 457 | { | 470 | { |
| 458 | unsigned long redzone_start; | 471 | unsigned long redzone_start; |
| 459 | unsigned long redzone_end; | 472 | unsigned long redzone_end; |
| @@ -471,7 +484,7 @@ void * __must_check kasan_kmalloc(struct kmem_cache *cache, const void *object, | |||
| 471 | KASAN_SHADOW_SCALE_SIZE); | 484 | KASAN_SHADOW_SCALE_SIZE); |
| 472 | 485 | ||
| 473 | if (IS_ENABLED(CONFIG_KASAN_SW_TAGS)) | 486 | if (IS_ENABLED(CONFIG_KASAN_SW_TAGS)) |
| 474 | tag = assign_tag(cache, object, false); | 487 | tag = assign_tag(cache, object, false, keep_tag); |
| 475 | 488 | ||
| 476 | /* Tag is ignored in set_tag without CONFIG_KASAN_SW_TAGS */ | 489 | /* Tag is ignored in set_tag without CONFIG_KASAN_SW_TAGS */ |
| 477 | kasan_unpoison_shadow(set_tag(object, tag), size); | 490 | kasan_unpoison_shadow(set_tag(object, tag), size); |
| @@ -483,6 +496,18 @@ void * __must_check kasan_kmalloc(struct kmem_cache *cache, const void *object, | |||
| 483 | 496 | ||
| 484 | return set_tag(object, tag); | 497 | return set_tag(object, tag); |
| 485 | } | 498 | } |
| 499 | |||
| 500 | void * __must_check kasan_slab_alloc(struct kmem_cache *cache, void *object, | ||
| 501 | gfp_t flags) | ||
| 502 | { | ||
| 503 | return __kasan_kmalloc(cache, object, cache->object_size, flags, false); | ||
| 504 | } | ||
| 505 | |||
| 506 | void * __must_check kasan_kmalloc(struct kmem_cache *cache, const void *object, | ||
| 507 | size_t size, gfp_t flags) | ||
| 508 | { | ||
| 509 | return __kasan_kmalloc(cache, object, size, flags, true); | ||
| 510 | } | ||
| 486 | EXPORT_SYMBOL(kasan_kmalloc); | 511 | EXPORT_SYMBOL(kasan_kmalloc); |
| 487 | 512 | ||
| 488 | void * __must_check kasan_kmalloc_large(const void *ptr, size_t size, | 513 | void * __must_check kasan_kmalloc_large(const void *ptr, size_t size, |
| @@ -522,7 +547,8 @@ void * __must_check kasan_krealloc(const void *object, size_t size, gfp_t flags) | |||
| 522 | if (unlikely(!PageSlab(page))) | 547 | if (unlikely(!PageSlab(page))) |
| 523 | return kasan_kmalloc_large(object, size, flags); | 548 | return kasan_kmalloc_large(object, size, flags); |
| 524 | else | 549 | else |
| 525 | return kasan_kmalloc(page->slab_cache, object, size, flags); | 550 | return __kasan_kmalloc(page->slab_cache, object, size, |
| 551 | flags, true); | ||
| 526 | } | 552 | } |
| 527 | 553 | ||
| 528 | void kasan_poison_kfree(void *ptr, unsigned long ip) | 554 | void kasan_poison_kfree(void *ptr, unsigned long ip) |
