File Index
Files and directories
Sign in
FILE

report_tags.c

File preview with syntax highlighting.

linux-6.19.14/mm/kasan/report_tags.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
  4 * Copyright (c) 2020 Google, Inc.
  5 */
  6
  7#include <linux/atomic.h>
  8
  9#include "kasan.h"
 10#include "../slab.h"
 11
 12extern struct kasan_stack_ring stack_ring;
 13
 14static const char *get_common_bug_type(struct kasan_report_info *info)
 15{
 16	/*
 17	 * If access_size is a negative number, then it has reason to be
 18	 * defined as out-of-bounds bug type.
 19	 *
 20	 * Casting negative numbers to size_t would indeed turn up as
 21	 * a large size_t and its value will be larger than ULONG_MAX/2,
 22	 * so that this can qualify as out-of-bounds.
 23	 */
 24	if (info->access_addr + info->access_size < info->access_addr)
 25		return "out-of-bounds";
 26
 27	return "invalid-access";
 28}
 29
 30void kasan_complete_mode_report_info(struct kasan_report_info *info)
 31{
 32	unsigned long flags;
 33	u64 pos;
 34	struct kasan_stack_ring_entry *entry;
 35	bool alloc_found = false, free_found = false;
 36
 37	if ((!info->cache || !info->object) && !info->bug_type) {
 38		info->bug_type = get_common_bug_type(info);
 39		return;
 40	}
 41
 42	write_lock_irqsave(&stack_ring.lock, flags);
 43
 44	pos = atomic64_read(&stack_ring.pos);
 45
 46	/*
 47	 * The loop below tries to find stack ring entries relevant to the
 48	 * buggy object. This is a best-effort process.
 49	 *
 50	 * First, another object with the same tag can be allocated in place of
 51	 * the buggy object. Also, since the number of entries is limited, the
 52	 * entries relevant to the buggy object can be overwritten.
 53	 */
 54
 55	for (u64 i = pos - 1; i != pos - 1 - stack_ring.size; i--) {
 56		if (alloc_found && free_found)
 57			break;
 58
 59		entry = &stack_ring.entries[i % stack_ring.size];
 60
 61		if (kasan_reset_tag(entry->ptr) != info->object ||
 62		    get_tag(entry->ptr) != get_tag(info->access_addr) ||
 63		    info->cache->object_size != entry->size)
 64			continue;
 65
 66		if (entry->is_free) {
 67			/*
 68			 * Second free of the same object.
 69			 * Give up on trying to find the alloc entry.
 70			 */
 71			if (free_found)
 72				break;
 73
 74			memcpy(&info->free_track, &entry->track,
 75			       sizeof(info->free_track));
 76			free_found = true;
 77
 78			/*
 79			 * If a free entry is found first, the bug is likely
 80			 * a use-after-free.
 81			 */
 82			if (!info->bug_type)
 83				info->bug_type = "slab-use-after-free";
 84		} else {
 85			/* Second alloc of the same object. Give up. */
 86			if (alloc_found)
 87				break;
 88
 89			memcpy(&info->alloc_track, &entry->track,
 90			       sizeof(info->alloc_track));
 91			alloc_found = true;
 92
 93			/*
 94			 * If an alloc entry is found first, the bug is likely
 95			 * an out-of-bounds.
 96			 */
 97			if (!info->bug_type)
 98				info->bug_type = "slab-out-of-bounds";
 99		}
100	}
101
102	write_unlock_irqrestore(&stack_ring.lock, flags);
103
104	/* Assign the common bug type if no entries were found. */
105	if (!info->bug_type)
106		info->bug_type = get_common_bug_type(info);
107}
~/ Read-only file preview.