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

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

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ 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.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * KMSAN compiler API.
  4  *
  5  * This file implements __msan_XXX hooks that Clang inserts into the code
  6  * compiled with -fsanitize=kernel-memory.
  7  * See Documentation/dev-tools/kmsan.rst for more information on how KMSAN
  8  * instrumentation works.
  9  *
 10  * Copyright (C) 2017-2022 Google LLC
 11  * Author: Alexander Potapenko <glider@google.com>
 12  *
 13  */
 14 
 15 #include "kmsan.h"
 16 #include <linux/gfp.h>
 17 #include <linux/kmsan.h>
 18 #include <linux/kmsan_string.h>
 19 #include <linux/mm.h>
 20 #include <linux/uaccess.h>
 21 
 22 static inline bool is_bad_asm_addr(void *addr, uintptr_t size, bool is_store)
 23 {
 24         if (IS_ENABLED(CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE) &&
 25             (u64)addr < TASK_SIZE)
 26                 return true;
 27         if (!kmsan_get_metadata(addr, KMSAN_META_SHADOW))
 28                 return true;
 29         return false;
 30 }
 31 
 32 static inline struct shadow_origin_ptr
 33 get_shadow_origin_ptr(void *addr, u64 size, bool store)
 34 {
 35         unsigned long ua_flags = user_access_save();
 36         struct shadow_origin_ptr ret;
 37 
 38         ret = kmsan_get_shadow_origin_ptr(addr, size, store);
 39         user_access_restore(ua_flags);
 40         return ret;
 41 }
 42 
 43 /*
 44  * KMSAN instrumentation functions follow. They are not declared elsewhere in
 45  * the kernel code, so they are preceded by prototypes, to silence
 46  * -Wmissing-prototypes warnings.
 47  */
 48 
 49 /* Get shadow and origin pointers for a memory load with non-standard size. */
 50 struct shadow_origin_ptr __msan_metadata_ptr_for_load_n(void *addr,
 51                                                         uintptr_t size);
 52 struct shadow_origin_ptr __msan_metadata_ptr_for_load_n(void *addr,
 53                                                         uintptr_t size)
 54 {
 55         return get_shadow_origin_ptr(addr, size, /*store*/ false);
 56 }
 57 EXPORT_SYMBOL(__msan_metadata_ptr_for_load_n);
 58 
 59 /* Get shadow and origin pointers for a memory store with non-standard size. */
 60 struct shadow_origin_ptr __msan_metadata_ptr_for_store_n(void *addr,
 61                                                          uintptr_t size);
 62 struct shadow_origin_ptr __msan_metadata_ptr_for_store_n(void *addr,
 63                                                          uintptr_t size)
 64 {
 65         return get_shadow_origin_ptr(addr, size, /*store*/ true);
 66 }
 67 EXPORT_SYMBOL(__msan_metadata_ptr_for_store_n);
 68 
 69 /*
 70  * Declare functions that obtain shadow/origin pointers for loads and stores
 71  * with fixed size.
 72  */
 73 #define DECLARE_METADATA_PTR_GETTER(size)                                  \
 74         struct shadow_origin_ptr __msan_metadata_ptr_for_load_##size(      \
 75                 void *addr);                                               \
 76         struct shadow_origin_ptr __msan_metadata_ptr_for_load_##size(      \
 77                 void *addr)                                                \
 78         {                                                                  \
 79                 return get_shadow_origin_ptr(addr, size, /*store*/ false); \
 80         }                                                                  \
 81         EXPORT_SYMBOL(__msan_metadata_ptr_for_load_##size);                \
 82         struct shadow_origin_ptr __msan_metadata_ptr_for_store_##size(     \
 83                 void *addr);                                               \
 84         struct shadow_origin_ptr __msan_metadata_ptr_for_store_##size(     \
 85                 void *addr)                                                \
 86         {                                                                  \
 87                 return get_shadow_origin_ptr(addr, size, /*store*/ true);  \
 88         }                                                                  \
 89         EXPORT_SYMBOL(__msan_metadata_ptr_for_store_##size)
 90 
 91 DECLARE_METADATA_PTR_GETTER(1);
 92 DECLARE_METADATA_PTR_GETTER(2);
 93 DECLARE_METADATA_PTR_GETTER(4);
 94 DECLARE_METADATA_PTR_GETTER(8);
 95 
 96 /*
 97  * Handle a memory store performed by inline assembly. KMSAN conservatively
 98  * attempts to unpoison the outputs of asm() directives to prevent false
 99  * positives caused by missed stores.
100  *
101  * __msan_instrument_asm_store() may be called for inline assembly code when
102  * entering or leaving IRQ. We omit the check for kmsan_in_runtime() to ensure
103  * the memory written to in these cases is also marked as initialized.
104  */
105 void __msan_instrument_asm_store(void *addr, uintptr_t size);
106 void __msan_instrument_asm_store(void *addr, uintptr_t size)
107 {
108         unsigned long ua_flags;
109 
110         if (!kmsan_enabled)
111                 return;
112 
113         ua_flags = user_access_save();
114         /*
115          * Most of the accesses are below 32 bytes. The exceptions so far are
116          * clwb() (64 bytes), FPU state (512 bytes) and chsc() (4096 bytes).
117          */
118         if (size > 4096) {
119                 WARN_ONCE(1, "assembly store size too big: %ld\n", size);
120                 size = 8;
121         }
122         if (is_bad_asm_addr(addr, size, /*is_store*/ true)) {
123                 user_access_restore(ua_flags);
124                 return;
125         }
126         /* Unpoisoning the memory on best effort. */
127         kmsan_internal_unpoison_memory(addr, size, /*checked*/ false);
128         user_access_restore(ua_flags);
129 }
130 EXPORT_SYMBOL(__msan_instrument_asm_store);
131 
132 /*
133  * KMSAN instrumentation pass replaces LLVM memcpy, memmove and memset
134  * intrinsics with calls to respective __msan_ functions. We use
135  * get_param0_metadata() and set_retval_metadata() to store the shadow/origin
136  * values for the destination argument of these functions and use them for the
137  * functions' return values.
138  */
139 static inline void get_param0_metadata(u64 *shadow,
140                                        depot_stack_handle_t *origin)
141 {
142         struct kmsan_ctx *ctx = kmsan_get_context();
143 
144         *shadow = *(u64 *)(ctx->cstate.param_tls);
145         *origin = ctx->cstate.param_origin_tls[0];
146 }
147 
148 static inline void set_retval_metadata(u64 shadow, depot_stack_handle_t origin)
149 {
150         struct kmsan_ctx *ctx = kmsan_get_context();
151 
152         *(u64 *)(ctx->cstate.retval_tls) = shadow;
153         ctx->cstate.retval_origin_tls = origin;
154 }
155 
156 /* Handle llvm.memmove intrinsic. */
157 void *__msan_memmove(void *dst, const void *src, uintptr_t n);
158 void *__msan_memmove(void *dst, const void *src, uintptr_t n)
159 {
160         depot_stack_handle_t origin;
161         void *result;
162         u64 shadow;
163 
164         get_param0_metadata(&shadow, &origin);
165         result = __memmove(dst, src, n);
166         if (!n)
167                 /* Some people call memmove() with zero length. */
168                 return result;
169         if (!kmsan_enabled || kmsan_in_runtime())
170                 return result;
171 
172         kmsan_enter_runtime();
173         kmsan_internal_memmove_metadata(dst, (void *)src, n);
174         kmsan_leave_runtime();
175 
176         set_retval_metadata(shadow, origin);
177         return result;
178 }
179 EXPORT_SYMBOL(__msan_memmove);
180 
181 /* Handle llvm.memcpy intrinsic. */
182 void *__msan_memcpy(void *dst, const void *src, uintptr_t n);
183 void *__msan_memcpy(void *dst, const void *src, uintptr_t n)
184 {
185         depot_stack_handle_t origin;
186         void *result;
187         u64 shadow;
188 
189         get_param0_metadata(&shadow, &origin);
190         result = __memcpy(dst, src, n);
191         if (!n)
192                 /* Some people call memcpy() with zero length. */
193                 return result;
194 
195         if (!kmsan_enabled || kmsan_in_runtime())
196                 return result;
197 
198         kmsan_enter_runtime();
199         /* Using memmove instead of memcpy doesn't affect correctness. */
200         kmsan_internal_memmove_metadata(dst, (void *)src, n);
201         kmsan_leave_runtime();
202 
203         set_retval_metadata(shadow, origin);
204         return result;
205 }
206 EXPORT_SYMBOL(__msan_memcpy);
207 
208 /* Handle llvm.memset intrinsic. */
209 void *__msan_memset(void *dst, int c, uintptr_t n);
210 void *__msan_memset(void *dst, int c, uintptr_t n)
211 {
212         depot_stack_handle_t origin;
213         void *result;
214         u64 shadow;
215 
216         get_param0_metadata(&shadow, &origin);
217         result = __memset(dst, c, n);
218         if (!kmsan_enabled || kmsan_in_runtime())
219                 return result;
220 
221         kmsan_enter_runtime();
222         /*
223          * Clang doesn't pass parameter metadata here, so it is impossible to
224          * use shadow of @c to set up the shadow for @dst.
225          */
226         kmsan_internal_unpoison_memory(dst, n, /*checked*/ false);
227         kmsan_leave_runtime();
228 
229         set_retval_metadata(shadow, origin);
230         return result;
231 }
232 EXPORT_SYMBOL(__msan_memset);
233 
234 /*
235  * Create a new origin from an old one. This is done when storing an
236  * uninitialized value to memory. When reporting an error, KMSAN unrolls and
237  * prints the whole chain of stores that preceded the use of this value.
238  */
239 depot_stack_handle_t __msan_chain_origin(depot_stack_handle_t origin);
240 depot_stack_handle_t __msan_chain_origin(depot_stack_handle_t origin)
241 {
242         depot_stack_handle_t ret = 0;
243         unsigned long ua_flags;
244 
245         if (!kmsan_enabled || kmsan_in_runtime())
246                 return ret;
247 
248         ua_flags = user_access_save();
249 
250         /* Creating new origins may allocate memory. */
251         kmsan_enter_runtime();
252         ret = kmsan_internal_chain_origin(origin);
253         kmsan_leave_runtime();
254         user_access_restore(ua_flags);
255         return ret;
256 }
257 EXPORT_SYMBOL(__msan_chain_origin);
258 
259 /* Poison a local variable when entering a function. */
260 void __msan_poison_alloca(void *address, uintptr_t size, char *descr);
261 void __msan_poison_alloca(void *address, uintptr_t size, char *descr)
262 {
263         depot_stack_handle_t handle;
264         unsigned long entries[4];
265         unsigned long ua_flags;
266 
267         if (!kmsan_enabled || kmsan_in_runtime())
268                 return;
269 
270         ua_flags = user_access_save();
271         entries[0] = KMSAN_ALLOCA_MAGIC_ORIGIN;
272         entries[1] = (u64)descr;
273         entries[2] = (u64)__builtin_return_address(0);
274         /*
275          * With frame pointers enabled, it is possible to quickly fetch the
276          * second frame of the caller stack without calling the unwinder.
277          * Without them, simply do not bother.
278          */
279         if (IS_ENABLED(CONFIG_UNWINDER_FRAME_POINTER))
280                 entries[3] = (u64)__builtin_return_address(1);
281         else
282                 entries[3] = 0;
283 
284         /* stack_depot_save() may allocate memory. */
285         kmsan_enter_runtime();
286         handle = stack_depot_save(entries, ARRAY_SIZE(entries), __GFP_HIGH);
287         kmsan_leave_runtime();
288 
289         kmsan_internal_set_shadow_origin(address, size, -1, handle,
290                                          /*checked*/ true);
291         user_access_restore(ua_flags);
292 }
293 EXPORT_SYMBOL(__msan_poison_alloca);
294 
295 /* Unpoison a local variable. */
296 void __msan_unpoison_alloca(void *address, uintptr_t size);
297 void __msan_unpoison_alloca(void *address, uintptr_t size)
298 {
299         if (!kmsan_enabled || kmsan_in_runtime())
300                 return;
301 
302         kmsan_enter_runtime();
303         kmsan_internal_unpoison_memory(address, size, /*checked*/ true);
304         kmsan_leave_runtime();
305 }
306 EXPORT_SYMBOL(__msan_unpoison_alloca);
307 
308 /*
309  * Report that an uninitialized value with the given origin was used in a way
310  * that constituted undefined behavior.
311  */
312 void __msan_warning(u32 origin);
313 void __msan_warning(u32 origin)
314 {
315         if (!kmsan_enabled || kmsan_in_runtime())
316                 return;
317         kmsan_enter_runtime();
318         kmsan_report(origin, /*address*/ NULL, /*size*/ 0,
319                      /*off_first*/ 0, /*off_last*/ 0, /*user_addr*/ NULL,
320                      REASON_ANY);
321         kmsan_leave_runtime();
322 }
323 EXPORT_SYMBOL(__msan_warning);
324 
325 /*
326  * At the beginning of an instrumented function, obtain the pointer to
327  * `struct kmsan_context_state` holding the metadata for function parameters.
328  */
329 struct kmsan_context_state *__msan_get_context_state(void);
330 struct kmsan_context_state *__msan_get_context_state(void)
331 {
332         return &kmsan_get_context()->cstate;
333 }
334 EXPORT_SYMBOL(__msan_get_context_state);
335 

~ [ 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