Skip to content

Commit 773688a

Browse files
xairyakpm00
authored andcommitted
kasan: use stack_depot_put for Generic mode
Evict alloc/free stack traces from the stack depot for Generic KASAN once they are evicted from the quaratine. For auxiliary stack traces, evict the oldest stack trace once a new one is saved (KASAN only keeps references to the last two). Also evict all saved stack traces on krealloc. To avoid double-evicting and mis-evicting stack traces (in case KASAN's metadata was corrupted), reset KASAN's per-object metadata that stores stack depot handles when the object is initialized and when it's evicted from the quarantine. Note that stack_depot_put is no-op if the handle is 0. Link: https://lkml.kernel.org/r/5cef104d9b842899489b4054fe8d1339a71acee0.1700502145.git.andreyknvl@google.com Signed-off-by: Andrey Konovalov <andreyknvl@google.com> Reviewed-by: Marco Elver <elver@google.com> Cc: Alexander Potapenko <glider@google.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: Evgenii Stepanov <eugenis@google.com> Cc: Oscar Salvador <osalvador@suse.de> Cc: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 2d55246 commit 773688a

File tree

3 files changed

+40
-11
lines changed

3 files changed

+40
-11
lines changed

mm/kasan/common.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ depot_stack_handle_t kasan_save_stack(gfp_t flags, depot_flags_t depot_flags)
5050
void kasan_set_track(struct kasan_track *track, gfp_t flags)
5151
{
5252
track->pid = current->pid;
53-
track->stack = kasan_save_stack(flags, STACK_DEPOT_FLAG_CAN_ALLOC);
53+
track->stack = kasan_save_stack(flags,
54+
STACK_DEPOT_FLAG_CAN_ALLOC | STACK_DEPOT_FLAG_GET);
5455
}
5556

5657
#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)

mm/kasan/generic.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -449,10 +449,14 @@ struct kasan_free_meta *kasan_get_free_meta(struct kmem_cache *cache,
449449
void kasan_init_object_meta(struct kmem_cache *cache, const void *object)
450450
{
451451
struct kasan_alloc_meta *alloc_meta;
452+
struct kasan_free_meta *free_meta;
452453

453454
alloc_meta = kasan_get_alloc_meta(cache, object);
454455
if (alloc_meta)
455456
__memset(alloc_meta, 0, sizeof(*alloc_meta));
457+
free_meta = kasan_get_free_meta(cache, object);
458+
if (free_meta)
459+
__memset(free_meta, 0, sizeof(*free_meta));
456460
}
457461

458462
size_t kasan_metadata_size(struct kmem_cache *cache, bool in_object)
@@ -489,27 +493,37 @@ static void __kasan_record_aux_stack(void *addr, depot_flags_t depot_flags)
489493
if (!alloc_meta)
490494
return;
491495

496+
stack_depot_put(alloc_meta->aux_stack[1]);
492497
alloc_meta->aux_stack[1] = alloc_meta->aux_stack[0];
493498
alloc_meta->aux_stack[0] = kasan_save_stack(0, depot_flags);
494499
}
495500

496501
void kasan_record_aux_stack(void *addr)
497502
{
498-
return __kasan_record_aux_stack(addr, STACK_DEPOT_FLAG_CAN_ALLOC);
503+
return __kasan_record_aux_stack(addr,
504+
STACK_DEPOT_FLAG_CAN_ALLOC | STACK_DEPOT_FLAG_GET);
499505
}
500506

501507
void kasan_record_aux_stack_noalloc(void *addr)
502508
{
503-
return __kasan_record_aux_stack(addr, 0);
509+
return __kasan_record_aux_stack(addr, STACK_DEPOT_FLAG_GET);
504510
}
505511

506512
void kasan_save_alloc_info(struct kmem_cache *cache, void *object, gfp_t flags)
507513
{
508514
struct kasan_alloc_meta *alloc_meta;
509515

510516
alloc_meta = kasan_get_alloc_meta(cache, object);
511-
if (alloc_meta)
512-
kasan_set_track(&alloc_meta->alloc_track, flags);
517+
if (!alloc_meta)
518+
return;
519+
520+
/* Evict previous stack traces (might exist for krealloc). */
521+
stack_depot_put(alloc_meta->alloc_track.stack);
522+
stack_depot_put(alloc_meta->aux_stack[0]);
523+
stack_depot_put(alloc_meta->aux_stack[1]);
524+
__memset(alloc_meta, 0, sizeof(*alloc_meta));
525+
526+
kasan_set_track(&alloc_meta->alloc_track, flags);
513527
}
514528

515529
void kasan_save_free_info(struct kmem_cache *cache, void *object)

mm/kasan/quarantine.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,22 @@ static void *qlink_to_object(struct qlist_node *qlink, struct kmem_cache *cache)
143143
static void qlink_free(struct qlist_node *qlink, struct kmem_cache *cache)
144144
{
145145
void *object = qlink_to_object(qlink, cache);
146-
struct kasan_free_meta *meta = kasan_get_free_meta(cache, object);
146+
struct kasan_alloc_meta *alloc_meta = kasan_get_alloc_meta(cache, object);
147+
struct kasan_free_meta *free_meta = kasan_get_free_meta(cache, object);
147148
unsigned long flags;
148149

149-
if (IS_ENABLED(CONFIG_SLAB))
150-
local_irq_save(flags);
150+
if (alloc_meta) {
151+
stack_depot_put(alloc_meta->alloc_track.stack);
152+
stack_depot_put(alloc_meta->aux_stack[0]);
153+
stack_depot_put(alloc_meta->aux_stack[1]);
154+
__memset(alloc_meta, 0, sizeof(*alloc_meta));
155+
}
156+
157+
if (free_meta &&
158+
*(u8 *)kasan_mem_to_shadow(object) == KASAN_SLAB_FREETRACK) {
159+
stack_depot_put(free_meta->free_track.stack);
160+
free_meta->free_track.stack = 0;
161+
}
151162

152163
/*
153164
* If init_on_free is enabled and KASAN's free metadata is stored in
@@ -157,14 +168,17 @@ static void qlink_free(struct qlist_node *qlink, struct kmem_cache *cache)
157168
*/
158169
if (slab_want_init_on_free(cache) &&
159170
cache->kasan_info.free_meta_offset == 0)
160-
memzero_explicit(meta, sizeof(*meta));
171+
memzero_explicit(free_meta, sizeof(*free_meta));
161172

162173
/*
163-
* As the object now gets freed from the quarantine, assume that its
164-
* free track is no longer valid.
174+
* As the object now gets freed from the quarantine,
175+
* take note that its free track is no longer exists.
165176
*/
166177
*(u8 *)kasan_mem_to_shadow(object) = KASAN_SLAB_FREE;
167178

179+
if (IS_ENABLED(CONFIG_SLAB))
180+
local_irq_save(flags);
181+
168182
___cache_free(cache, object, _THIS_IP_);
169183

170184
if (IS_ENABLED(CONFIG_SLAB))

0 commit comments

Comments
 (0)