ecede06ef374aafc7cf0d5f275667ee0499a956a
[sfrench/cifs-2.6.git] / mm / kasan / report_tags.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
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 }