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