diff options
Diffstat (limited to 'mm/kasan/kasan.c')
-rw-r--r-- | mm/kasan/kasan.c | 65 |
1 files changed, 29 insertions, 36 deletions
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c index b6f99e81bfeb..88af13c00d3c 100644 --- a/mm/kasan/kasan.c +++ b/mm/kasan/kasan.c | |||
@@ -442,11 +442,6 @@ void kasan_poison_object_data(struct kmem_cache *cache, void *object) | |||
442 | kasan_poison_shadow(object, | 442 | kasan_poison_shadow(object, |
443 | round_up(cache->object_size, KASAN_SHADOW_SCALE_SIZE), | 443 | round_up(cache->object_size, KASAN_SHADOW_SCALE_SIZE), |
444 | KASAN_KMALLOC_REDZONE); | 444 | KASAN_KMALLOC_REDZONE); |
445 | if (cache->flags & SLAB_KASAN) { | ||
446 | struct kasan_alloc_meta *alloc_info = | ||
447 | get_alloc_info(cache, object); | ||
448 | alloc_info->state = KASAN_STATE_INIT; | ||
449 | } | ||
450 | } | 445 | } |
451 | 446 | ||
452 | static inline int in_irqentry_text(unsigned long ptr) | 447 | static inline int in_irqentry_text(unsigned long ptr) |
@@ -510,6 +505,17 @@ struct kasan_free_meta *get_free_info(struct kmem_cache *cache, | |||
510 | return (void *)object + cache->kasan_info.free_meta_offset; | 505 | return (void *)object + cache->kasan_info.free_meta_offset; |
511 | } | 506 | } |
512 | 507 | ||
508 | void kasan_init_slab_obj(struct kmem_cache *cache, const void *object) | ||
509 | { | ||
510 | struct kasan_alloc_meta *alloc_info; | ||
511 | |||
512 | if (!(cache->flags & SLAB_KASAN)) | ||
513 | return; | ||
514 | |||
515 | alloc_info = get_alloc_info(cache, object); | ||
516 | __memset(alloc_info, 0, sizeof(*alloc_info)); | ||
517 | } | ||
518 | |||
513 | void kasan_slab_alloc(struct kmem_cache *cache, void *object, gfp_t flags) | 519 | void kasan_slab_alloc(struct kmem_cache *cache, void *object, gfp_t flags) |
514 | { | 520 | { |
515 | kasan_kmalloc(cache, object, cache->object_size, flags); | 521 | kasan_kmalloc(cache, object, cache->object_size, flags); |
@@ -529,34 +535,26 @@ static void kasan_poison_slab_free(struct kmem_cache *cache, void *object) | |||
529 | 535 | ||
530 | bool kasan_slab_free(struct kmem_cache *cache, void *object) | 536 | bool kasan_slab_free(struct kmem_cache *cache, void *object) |
531 | { | 537 | { |
538 | s8 shadow_byte; | ||
539 | |||
532 | /* RCU slabs could be legally used after free within the RCU period */ | 540 | /* RCU slabs could be legally used after free within the RCU period */ |
533 | if (unlikely(cache->flags & SLAB_DESTROY_BY_RCU)) | 541 | if (unlikely(cache->flags & SLAB_DESTROY_BY_RCU)) |
534 | return false; | 542 | return false; |
535 | 543 | ||
536 | if (likely(cache->flags & SLAB_KASAN)) { | 544 | shadow_byte = READ_ONCE(*(s8 *)kasan_mem_to_shadow(object)); |
537 | struct kasan_alloc_meta *alloc_info; | 545 | if (shadow_byte < 0 || shadow_byte >= KASAN_SHADOW_SCALE_SIZE) { |
538 | struct kasan_free_meta *free_info; | 546 | kasan_report_double_free(cache, object, shadow_byte); |
547 | return true; | ||
548 | } | ||
539 | 549 | ||
540 | alloc_info = get_alloc_info(cache, object); | 550 | kasan_poison_slab_free(cache, object); |
541 | free_info = get_free_info(cache, object); | ||
542 | 551 | ||
543 | switch (alloc_info->state) { | 552 | if (unlikely(!(cache->flags & SLAB_KASAN))) |
544 | case KASAN_STATE_ALLOC: | 553 | return false; |
545 | alloc_info->state = KASAN_STATE_QUARANTINE; | 554 | |
546 | quarantine_put(free_info, cache); | 555 | set_track(&get_alloc_info(cache, object)->free_track, GFP_NOWAIT); |
547 | set_track(&free_info->track, GFP_NOWAIT); | 556 | quarantine_put(get_free_info(cache, object), cache); |
548 | kasan_poison_slab_free(cache, object); | 557 | return true; |
549 | return true; | ||
550 | case KASAN_STATE_QUARANTINE: | ||
551 | case KASAN_STATE_FREE: | ||
552 | pr_err("Double free"); | ||
553 | dump_stack(); | ||
554 | break; | ||
555 | default: | ||
556 | break; | ||
557 | } | ||
558 | } | ||
559 | return false; | ||
560 | } | 558 | } |
561 | 559 | ||
562 | void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size, | 560 | void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size, |
@@ -565,7 +563,7 @@ void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size, | |||
565 | unsigned long redzone_start; | 563 | unsigned long redzone_start; |
566 | unsigned long redzone_end; | 564 | unsigned long redzone_end; |
567 | 565 | ||
568 | if (flags & __GFP_RECLAIM) | 566 | if (gfpflags_allow_blocking(flags)) |
569 | quarantine_reduce(); | 567 | quarantine_reduce(); |
570 | 568 | ||
571 | if (unlikely(object == NULL)) | 569 | if (unlikely(object == NULL)) |
@@ -579,14 +577,9 @@ void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size, | |||
579 | kasan_unpoison_shadow(object, size); | 577 | kasan_unpoison_shadow(object, size); |
580 | kasan_poison_shadow((void *)redzone_start, redzone_end - redzone_start, | 578 | kasan_poison_shadow((void *)redzone_start, redzone_end - redzone_start, |
581 | KASAN_KMALLOC_REDZONE); | 579 | KASAN_KMALLOC_REDZONE); |
582 | if (cache->flags & SLAB_KASAN) { | ||
583 | struct kasan_alloc_meta *alloc_info = | ||
584 | get_alloc_info(cache, object); | ||
585 | 580 | ||
586 | alloc_info->state = KASAN_STATE_ALLOC; | 581 | if (cache->flags & SLAB_KASAN) |
587 | alloc_info->alloc_size = size; | 582 | set_track(&get_alloc_info(cache, object)->alloc_track, flags); |
588 | set_track(&alloc_info->track, flags); | ||
589 | } | ||
590 | } | 583 | } |
591 | EXPORT_SYMBOL(kasan_kmalloc); | 584 | EXPORT_SYMBOL(kasan_kmalloc); |
592 | 585 | ||
@@ -596,7 +589,7 @@ void kasan_kmalloc_large(const void *ptr, size_t size, gfp_t flags) | |||
596 | unsigned long redzone_start; | 589 | unsigned long redzone_start; |
597 | unsigned long redzone_end; | 590 | unsigned long redzone_end; |
598 | 591 | ||
599 | if (flags & __GFP_RECLAIM) | 592 | if (gfpflags_allow_blocking(flags)) |
600 | quarantine_reduce(); | 593 | quarantine_reduce(); |
601 | 594 | ||
602 | if (unlikely(ptr == NULL)) | 595 | if (unlikely(ptr == NULL)) |