aboutsummaryrefslogtreecommitdiffstats
path: root/mm/kasan/kasan.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/kasan/kasan.c')
-rw-r--r--mm/kasan/kasan.c65
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
452static inline int in_irqentry_text(unsigned long ptr) 447static 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
508void 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
513void kasan_slab_alloc(struct kmem_cache *cache, void *object, gfp_t flags) 519void 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
530bool kasan_slab_free(struct kmem_cache *cache, void *object) 536bool 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
562void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size, 560void 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}
591EXPORT_SYMBOL(kasan_kmalloc); 584EXPORT_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))