Merge tag 'wq-for-6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
[linux-block.git] / mm / kasan / report_tags.c
CommitLineData
a0503b8a
KYL
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Copyright (c) 2020 Google, Inc.
5 */
6
7bc0584e
AK
7#include <linux/atomic.h>
8
a0503b8a 9#include "kasan.h"
a0503b8a 10
7bc0584e
AK
11extern struct kasan_stack_ring stack_ring;
12
1f538e1f 13static const char *get_common_bug_type(struct kasan_report_info *info)
a0503b8a 14{
a0503b8a
KYL
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}
b89933e9 28
59e6e098 29void kasan_complete_mode_report_info(struct kasan_report_info *info)
b89933e9 30{
7bc0584e
AK
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
dcc57966 40 if ((!info->cache || !info->object) && !info->bug_type) {
1f538e1f 41 info->bug_type = get_common_bug_type(info);
7bc0584e
AK
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
80b92bfe 58 for (u64 i = pos - 1; i != pos - 1 - stack_ring.size; i--) {
7bc0584e
AK
59 if (alloc_found && free_found)
60 break;
61
80b92bfe 62 entry = &stack_ring.entries[i % stack_ring.size];
7bc0584e
AK
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;
1f538e1f
AK
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)
8f17febb 92 info->bug_type = "slab-use-after-free";
7bc0584e
AK
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;
1f538e1f
AK
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";
7bc0584e
AK
108 }
109 }
110
111 write_unlock_irqrestore(&stack_ring.lock, flags);
1f538e1f
AK
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);
b89933e9 116}