Commit | Line | Data |
---|---|---|
f80be457 AP |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * KMSAN error reporting routines. | |
4 | * | |
5 | * Copyright (C) 2019-2022 Google LLC | |
6 | * Author: Alexander Potapenko <glider@google.com> | |
7 | * | |
8 | */ | |
9 | ||
10 | #include <linux/console.h> | |
11 | #include <linux/moduleparam.h> | |
12 | #include <linux/stackdepot.h> | |
13 | #include <linux/stacktrace.h> | |
14 | #include <linux/uaccess.h> | |
15 | ||
16 | #include "kmsan.h" | |
17 | ||
18 | static DEFINE_RAW_SPINLOCK(kmsan_report_lock); | |
19 | #define DESCR_SIZE 128 | |
20 | /* Protected by kmsan_report_lock */ | |
21 | static char report_local_descr[DESCR_SIZE]; | |
22 | int panic_on_kmsan __read_mostly; | |
23 | ||
24 | #ifdef MODULE_PARAM_PREFIX | |
25 | #undef MODULE_PARAM_PREFIX | |
26 | #endif | |
27 | #define MODULE_PARAM_PREFIX "kmsan." | |
28 | module_param_named(panic, panic_on_kmsan, int, 0); | |
29 | ||
30 | /* | |
31 | * Skip internal KMSAN frames. | |
32 | */ | |
33 | static int get_stack_skipnr(const unsigned long stack_entries[], | |
34 | int num_entries) | |
35 | { | |
36 | int len, skip; | |
37 | char buf[64]; | |
38 | ||
39 | for (skip = 0; skip < num_entries; ++skip) { | |
40 | len = scnprintf(buf, sizeof(buf), "%ps", | |
41 | (void *)stack_entries[skip]); | |
42 | ||
43 | /* Never show __msan_* or kmsan_* functions. */ | |
44 | if ((strnstr(buf, "__msan_", len) == buf) || | |
45 | (strnstr(buf, "kmsan_", len) == buf)) | |
46 | continue; | |
47 | ||
48 | /* | |
49 | * No match for runtime functions -- @skip entries to skip to | |
50 | * get to first frame of interest. | |
51 | */ | |
52 | break; | |
53 | } | |
54 | ||
55 | return skip; | |
56 | } | |
57 | ||
58 | /* | |
59 | * Currently the descriptions of locals generated by Clang look as follows: | |
60 | * ----local_name@function_name | |
61 | * We want to print only the name of the local, as other information in that | |
62 | * description can be confusing. | |
63 | * The meaningful part of the description is copied to a global buffer to avoid | |
64 | * allocating memory. | |
65 | */ | |
66 | static char *pretty_descr(char *descr) | |
67 | { | |
68 | int pos = 0, len = strlen(descr); | |
69 | ||
70 | for (int i = 0; i < len; i++) { | |
71 | if (descr[i] == '@') | |
72 | break; | |
73 | if (descr[i] == '-') | |
74 | continue; | |
75 | report_local_descr[pos] = descr[i]; | |
76 | if (pos + 1 == DESCR_SIZE) | |
77 | break; | |
78 | pos++; | |
79 | } | |
80 | report_local_descr[pos] = 0; | |
81 | return report_local_descr; | |
82 | } | |
83 | ||
84 | void kmsan_print_origin(depot_stack_handle_t origin) | |
85 | { | |
86 | unsigned long *entries = NULL, *chained_entries = NULL; | |
87 | unsigned int nr_entries, chained_nr_entries, skipnr; | |
88 | void *pc1 = NULL, *pc2 = NULL; | |
89 | depot_stack_handle_t head; | |
90 | unsigned long magic; | |
91 | char *descr = NULL; | |
92 | unsigned int depth; | |
93 | ||
94 | if (!origin) | |
95 | return; | |
96 | ||
97 | while (true) { | |
98 | nr_entries = stack_depot_fetch(origin, &entries); | |
99 | depth = kmsan_depth_from_eb(stack_depot_get_extra_bits(origin)); | |
100 | magic = nr_entries ? entries[0] : 0; | |
101 | if ((nr_entries == 4) && (magic == KMSAN_ALLOCA_MAGIC_ORIGIN)) { | |
102 | descr = (char *)entries[1]; | |
103 | pc1 = (void *)entries[2]; | |
104 | pc2 = (void *)entries[3]; | |
105 | pr_err("Local variable %s created at:\n", | |
106 | pretty_descr(descr)); | |
107 | if (pc1) | |
108 | pr_err(" %pSb\n", pc1); | |
109 | if (pc2) | |
110 | pr_err(" %pSb\n", pc2); | |
111 | break; | |
112 | } | |
113 | if ((nr_entries == 3) && (magic == KMSAN_CHAIN_MAGIC_ORIGIN)) { | |
114 | /* | |
115 | * Origin chains deeper than KMSAN_MAX_ORIGIN_DEPTH are | |
116 | * not stored, so the output may be incomplete. | |
117 | */ | |
118 | if (depth == KMSAN_MAX_ORIGIN_DEPTH) | |
119 | pr_err("<Zero or more stacks not recorded to save memory>\n\n"); | |
120 | head = entries[1]; | |
121 | origin = entries[2]; | |
122 | pr_err("Uninit was stored to memory at:\n"); | |
123 | chained_nr_entries = | |
124 | stack_depot_fetch(head, &chained_entries); | |
125 | kmsan_internal_unpoison_memory( | |
126 | chained_entries, | |
127 | chained_nr_entries * sizeof(*chained_entries), | |
128 | /*checked*/ false); | |
129 | skipnr = get_stack_skipnr(chained_entries, | |
130 | chained_nr_entries); | |
131 | stack_trace_print(chained_entries + skipnr, | |
132 | chained_nr_entries - skipnr, 0); | |
133 | pr_err("\n"); | |
134 | continue; | |
135 | } | |
136 | pr_err("Uninit was created at:\n"); | |
137 | if (nr_entries) { | |
138 | skipnr = get_stack_skipnr(entries, nr_entries); | |
139 | stack_trace_print(entries + skipnr, nr_entries - skipnr, | |
140 | 0); | |
141 | } else { | |
142 | pr_err("(stack is not available)\n"); | |
143 | } | |
144 | break; | |
145 | } | |
146 | } | |
147 | ||
148 | void kmsan_report(depot_stack_handle_t origin, void *address, int size, | |
149 | int off_first, int off_last, const void *user_addr, | |
150 | enum kmsan_bug_reason reason) | |
151 | { | |
152 | unsigned long stack_entries[KMSAN_STACK_DEPTH]; | |
153 | int num_stack_entries, skipnr; | |
154 | char *bug_type = NULL; | |
155 | unsigned long ua_flags; | |
156 | bool is_uaf; | |
157 | ||
158 | if (!kmsan_enabled) | |
159 | return; | |
160 | if (!current->kmsan_ctx.allow_reporting) | |
161 | return; | |
162 | if (!origin) | |
163 | return; | |
164 | ||
165 | current->kmsan_ctx.allow_reporting = false; | |
166 | ua_flags = user_access_save(); | |
167 | raw_spin_lock(&kmsan_report_lock); | |
168 | pr_err("=====================================================\n"); | |
169 | is_uaf = kmsan_uaf_from_eb(stack_depot_get_extra_bits(origin)); | |
170 | switch (reason) { | |
171 | case REASON_ANY: | |
172 | bug_type = is_uaf ? "use-after-free" : "uninit-value"; | |
173 | break; | |
174 | case REASON_COPY_TO_USER: | |
175 | bug_type = is_uaf ? "kernel-infoleak-after-free" : | |
176 | "kernel-infoleak"; | |
177 | break; | |
178 | case REASON_SUBMIT_URB: | |
179 | bug_type = is_uaf ? "kernel-usb-infoleak-after-free" : | |
180 | "kernel-usb-infoleak"; | |
181 | break; | |
182 | } | |
183 | ||
184 | num_stack_entries = | |
185 | stack_trace_save(stack_entries, KMSAN_STACK_DEPTH, 1); | |
186 | skipnr = get_stack_skipnr(stack_entries, num_stack_entries); | |
187 | ||
188 | pr_err("BUG: KMSAN: %s in %pSb\n", bug_type, | |
189 | (void *)stack_entries[skipnr]); | |
190 | stack_trace_print(stack_entries + skipnr, num_stack_entries - skipnr, | |
191 | 0); | |
192 | pr_err("\n"); | |
193 | ||
194 | kmsan_print_origin(origin); | |
195 | ||
196 | if (size) { | |
197 | pr_err("\n"); | |
198 | if (off_first == off_last) | |
199 | pr_err("Byte %d of %d is uninitialized\n", off_first, | |
200 | size); | |
201 | else | |
202 | pr_err("Bytes %d-%d of %d are uninitialized\n", | |
203 | off_first, off_last, size); | |
204 | } | |
205 | if (address) | |
206 | pr_err("Memory access of size %d starts at %px\n", size, | |
207 | address); | |
208 | if (user_addr && reason == REASON_COPY_TO_USER) | |
209 | pr_err("Data copied to user address %px\n", user_addr); | |
210 | pr_err("\n"); | |
211 | dump_stack_print_info(KERN_ERR); | |
212 | pr_err("=====================================================\n"); | |
213 | add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE); | |
214 | raw_spin_unlock(&kmsan_report_lock); | |
215 | if (panic_on_kmsan) | |
216 | panic("kmsan.panic set ...\n"); | |
217 | user_access_restore(ua_flags); | |
218 | current->kmsan_ctx.allow_reporting = true; | |
219 | } |