~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/mm/kmsan/report.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php