subr_asan.c revision 1.1 1 /* $NetBSD: subr_asan.c,v 1.1 2018/10/31 06:26:26 maxv Exp $ */
2
3 /*
4 * Copyright (c) 2018 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Maxime Villard.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: subr_asan.c,v 1.1 2018/10/31 06:26:26 maxv Exp $");
34
35 #include <sys/param.h>
36 #include <sys/device.h>
37 #include <sys/kernel.h>
38 #include <sys/param.h>
39 #include <sys/conf.h>
40 #include <sys/systm.h>
41 #include <sys/types.h>
42 #include <sys/asan.h>
43
44 #include <uvm/uvm.h>
45
46 /* ASAN constants. Part of the compiler ABI. */
47 #define KASAN_SHADOW_SCALE_SHIFT 3
48 #define KASAN_SHADOW_SCALE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT)
49 #define KASAN_SHADOW_MASK (KASAN_SHADOW_SCALE_SIZE - 1)
50
51 /* The MD code. */
52 #include <machine/asan.h>
53
54 /* Our redzone values. */
55 #define KASAN_GLOBAL_REDZONE 0xFA
56 #define KASAN_MEMORY_REDZONE 0xFB
57
58 /* Stack redzone values. Part of the compiler ABI. */
59 #define KASAN_STACK_LEFT 0xF1
60 #define KASAN_STACK_MID 0xF2
61 #define KASAN_STACK_RIGHT 0xF3
62 #define KASAN_STACK_PARTIAL 0xF4
63 #define KASAN_USE_AFTER_SCOPE 0xF8
64
65 /* ASAN ABI version. */
66 #if defined(__clang__) && (__clang_major__ - 0 >= 6)
67 #define ASAN_ABI_VERSION 8
68 #elif __GNUC_PREREQ__(7, 1) && !defined(__clang__)
69 #define ASAN_ABI_VERSION 8
70 #elif __GNUC_PREREQ__(6, 1) && !defined(__clang__)
71 #define ASAN_ABI_VERSION 6
72 #else
73 #error "Unsupported compiler version"
74 #endif
75
76 #define __RET_ADDR (unsigned long)__builtin_return_address(0)
77
78 /* Global variable descriptor. Part of the compiler ABI. */
79 struct __asan_global_source_location {
80 const char *filename;
81 int line_no;
82 int column_no;
83 };
84 struct __asan_global {
85 const void *beg; /* address of the global variable */
86 size_t size; /* size of the global variable */
87 size_t size_with_redzone; /* size with the redzone */
88 const void *name; /* name of the variable */
89 const void *module_name; /* name of the module where the var is declared */
90 unsigned long has_dynamic_init; /* the var has dyn initializer (c++) */
91 struct __asan_global_source_location *location;
92 #if ASAN_ABI_VERSION >= 7
93 uintptr_t odr_indicator; /* the address of the ODR indicator symbol */
94 #endif
95 };
96
97 static bool kasan_enabled __read_mostly = false;
98
99 /* -------------------------------------------------------------------------- */
100
101 void
102 kasan_shadow_map(void *addr, size_t size)
103 {
104 size_t sz, npages, i;
105 vaddr_t sva, eva;
106
107 KASSERT((vaddr_t)addr % KASAN_SHADOW_SCALE_SIZE == 0);
108
109 sz = roundup(size, KASAN_SHADOW_SCALE_SIZE) / KASAN_SHADOW_SCALE_SIZE;
110
111 sva = (vaddr_t)kasan_md_addr_to_shad(addr);
112 eva = (vaddr_t)kasan_md_addr_to_shad(addr) + sz;
113
114 sva = rounddown(sva, PAGE_SIZE);
115 eva = roundup(eva, PAGE_SIZE);
116
117 npages = (eva - sva) / PAGE_SIZE;
118
119 KASSERT(sva >= KASAN_MD_SHADOW_START && eva < KASAN_MD_SHADOW_END);
120
121 for (i = 0; i < npages; i++) {
122 kasan_md_shadow_map_page(sva + i * PAGE_SIZE);
123 }
124 }
125
126 static void
127 kasan_ctors(void)
128 {
129 extern uint64_t __CTOR_LIST__, __CTOR_END__;
130 size_t nentries, i;
131 uint64_t *ptr;
132
133 nentries = ((size_t)&__CTOR_END__ - (size_t)&__CTOR_LIST__) /
134 sizeof(uintptr_t);
135
136 ptr = &__CTOR_LIST__;
137 for (i = 0; i < nentries; i++) {
138 void (*func)(void);
139
140 func = (void *)(*ptr);
141 (*func)();
142
143 ptr++;
144 }
145 }
146
147 void
148 kasan_early_init(void *stack)
149 {
150 kasan_md_early_init(stack);
151 }
152
153 void
154 kasan_init(void)
155 {
156 /* MD initialization. */
157 kasan_md_init();
158
159 /* Now officially enabled. */
160 kasan_enabled = true;
161
162 /* Call the ASAN constructors. */
163 kasan_ctors();
164 }
165
166 static void
167 kasan_report(unsigned long addr, size_t size, bool write, unsigned long pc)
168 {
169 printf("kASan: Unauthorized Access In %p: Addr %p [%zu byte%s, %s]\n",
170 (void *)pc, (void *)addr, size, (size > 1 ? "s" : ""),
171 (write ? "write" : "read"));
172 kasan_md_unwind();
173 }
174
175 static __always_inline void
176 kasan_shadow_1byte_markvalid(unsigned long addr)
177 {
178 int8_t *byte = kasan_md_addr_to_shad((void *)addr);
179 int8_t last = (addr & KASAN_SHADOW_MASK) + 1;
180
181 *byte = last;
182 }
183
184 static __always_inline void
185 kasan_shadow_Nbyte_fill(const void *addr, size_t size, uint8_t val)
186 {
187 void *shad;
188
189 if (__predict_false(size == 0))
190 return;
191 if (__predict_false(kasan_md_unsupported((vaddr_t)addr)))
192 return;
193
194 KASSERT((vaddr_t)addr % KASAN_SHADOW_SCALE_SIZE == 0);
195 KASSERT(size % KASAN_SHADOW_SCALE_SIZE == 0);
196
197 shad = (void *)kasan_md_addr_to_shad(addr);
198 size = size >> KASAN_SHADOW_SCALE_SHIFT;
199
200 __builtin_memset(shad, val, size);
201 }
202
203 void
204 kasan_add_redzone(size_t *size)
205 {
206 *size = roundup(*size, KASAN_SHADOW_SCALE_SIZE);
207 *size += KASAN_SHADOW_SCALE_SIZE;
208 }
209
210 static void
211 kasan_markmem(const void *addr, size_t size, bool valid)
212 {
213 size_t i;
214
215 KASSERT((vaddr_t)addr % KASAN_SHADOW_SCALE_SIZE == 0);
216
217 if (valid) {
218 for (i = 0; i < size; i++) {
219 kasan_shadow_1byte_markvalid((unsigned long)addr+i);
220 }
221 } else {
222 KASSERT(size % KASAN_SHADOW_SCALE_SIZE == 0);
223 kasan_shadow_Nbyte_fill(addr, size, KASAN_MEMORY_REDZONE);
224 }
225 }
226
227 void
228 kasan_softint(struct lwp *l)
229 {
230 const void *stk = (const void *)uvm_lwp_getuarea(l);
231
232 kasan_shadow_Nbyte_fill(stk, USPACE, 0);
233 }
234
235 void
236 kasan_alloc(const void *addr, size_t size, size_t sz_with_redz)
237 {
238 kasan_markmem(addr, sz_with_redz, false);
239 kasan_markmem(addr, size, true);
240 }
241
242 void
243 kasan_free(const void *addr, size_t sz_with_redz)
244 {
245 kasan_markmem(addr, sz_with_redz, true);
246 }
247
248 /* -------------------------------------------------------------------------- */
249
250 #define ADDR_CROSSES_SCALE_BOUNDARY(addr, size) \
251 (addr >> KASAN_SHADOW_SCALE_SHIFT) != \
252 ((addr + size - 1) >> KASAN_SHADOW_SCALE_SHIFT)
253
254 static __always_inline bool
255 kasan_shadow_1byte_isvalid(unsigned long addr)
256 {
257 int8_t *byte = kasan_md_addr_to_shad((void *)addr);
258 int8_t last = (addr & KASAN_SHADOW_MASK) + 1;
259
260 return __predict_true(*byte == 0 || last <= *byte);
261 }
262
263 static __always_inline bool
264 kasan_shadow_2byte_isvalid(unsigned long addr)
265 {
266 int8_t *byte, last;
267
268 if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 2)) {
269 return (kasan_shadow_1byte_isvalid(addr) &&
270 kasan_shadow_1byte_isvalid(addr+1));
271 }
272
273 byte = kasan_md_addr_to_shad((void *)addr);
274 last = ((addr + 1) & KASAN_SHADOW_MASK) + 1;
275
276 return __predict_true(*byte == 0 || last <= *byte);
277 }
278
279 static __always_inline bool
280 kasan_shadow_4byte_isvalid(unsigned long addr)
281 {
282 int8_t *byte, last;
283
284 if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 4)) {
285 return (kasan_shadow_2byte_isvalid(addr) &&
286 kasan_shadow_2byte_isvalid(addr+2));
287 }
288
289 byte = kasan_md_addr_to_shad((void *)addr);
290 last = ((addr + 3) & KASAN_SHADOW_MASK) + 1;
291
292 return __predict_true(*byte == 0 || last <= *byte);
293 }
294
295 static __always_inline bool
296 kasan_shadow_8byte_isvalid(unsigned long addr)
297 {
298 int8_t *byte, last;
299
300 if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 8)) {
301 return (kasan_shadow_4byte_isvalid(addr) &&
302 kasan_shadow_4byte_isvalid(addr+4));
303 }
304
305 byte = kasan_md_addr_to_shad((void *)addr);
306 last = ((addr + 7) & KASAN_SHADOW_MASK) + 1;
307
308 return __predict_true(*byte == 0 || last <= *byte);
309 }
310
311 static __always_inline bool
312 kasan_shadow_Nbyte_isvalid(unsigned long addr, size_t size)
313 {
314 size_t i;
315
316 for (i = 0; i < size; i++) {
317 if (!kasan_shadow_1byte_isvalid(addr+i))
318 return false;
319 }
320
321 return true;
322 }
323
324 static __always_inline void
325 kasan_shadow_check(unsigned long addr, size_t size, bool write,
326 unsigned long retaddr)
327 {
328 bool valid;
329
330 if (__predict_false(!kasan_enabled))
331 return;
332 if (__predict_false(size == 0))
333 return;
334 if (__predict_false(kasan_md_unsupported(addr)))
335 return;
336
337 if (__builtin_constant_p(size)) {
338 switch (size) {
339 case 1:
340 valid = kasan_shadow_1byte_isvalid(addr);
341 break;
342 case 2:
343 valid = kasan_shadow_2byte_isvalid(addr);
344 break;
345 case 4:
346 valid = kasan_shadow_4byte_isvalid(addr);
347 break;
348 case 8:
349 valid = kasan_shadow_8byte_isvalid(addr);
350 break;
351 default:
352 valid = kasan_shadow_Nbyte_isvalid(addr, size);
353 break;
354 }
355 } else {
356 valid = kasan_shadow_Nbyte_isvalid(addr, size);
357 }
358
359 if (__predict_false(!valid)) {
360 kasan_report(addr, size, write, retaddr);
361 }
362 }
363
364 /* -------------------------------------------------------------------------- */
365
366 void *
367 kasan_memcpy(void *dst, const void *src, size_t len)
368 {
369 kasan_shadow_check((unsigned long)src, len, false, __RET_ADDR);
370 kasan_shadow_check((unsigned long)dst, len, true, __RET_ADDR);
371 return __builtin_memcpy(dst, src, len);
372 }
373
374 int
375 kasan_memcmp(const void *b1, const void *b2, size_t len)
376 {
377 kasan_shadow_check((unsigned long)b1, len, false, __RET_ADDR);
378 kasan_shadow_check((unsigned long)b2, len, false, __RET_ADDR);
379 return __builtin_memcmp(b1, b2, len);
380 }
381
382 void *
383 kasan_memset(void *b, int c, size_t len)
384 {
385 kasan_shadow_check((unsigned long)b, len, true, __RET_ADDR);
386 return __builtin_memset(b, c, len);
387 }
388
389 char *
390 kasan_strcpy(char *dst, const char *src)
391 {
392 char *save = dst;
393
394 while (1) {
395 kasan_shadow_check((unsigned long)src, 1, false, __RET_ADDR);
396 kasan_shadow_check((unsigned long)dst, 1, true, __RET_ADDR);
397 *dst = *src;
398 if (*src == '\0')
399 break;
400 src++, dst++;
401 }
402
403 return save;
404 }
405
406 int
407 kasan_strcmp(const char *s1, const char *s2)
408 {
409 while (1) {
410 kasan_shadow_check((unsigned long)s1, 1, false, __RET_ADDR);
411 kasan_shadow_check((unsigned long)s2, 1, false, __RET_ADDR);
412 if (*s1 != *s2)
413 break;
414 if (*s1 == '\0')
415 return 0;
416 s1++, s2++;
417 }
418
419 return (*(const unsigned char *)s1 - *(const unsigned char *)s2);
420 }
421
422 size_t
423 kasan_strlen(const char *str)
424 {
425 const char *s;
426
427 s = str;
428 while (1) {
429 kasan_shadow_check((unsigned long)s, 1, false, __RET_ADDR);
430 if (*s == '\0')
431 break;
432 s++;
433 }
434
435 return (s - str);
436 }
437
438 /* -------------------------------------------------------------------------- */
439
440 void __asan_register_globals(struct __asan_global *, size_t);
441 void __asan_unregister_globals(struct __asan_global *, size_t);
442
443 void
444 __asan_register_globals(struct __asan_global *globals, size_t n)
445 {
446 size_t i;
447
448 for (i = 0; i < n; i++) {
449 kasan_alloc(globals[i].beg, globals[i].size,
450 globals[i].size_with_redzone);
451 }
452 }
453
454 void
455 __asan_unregister_globals(struct __asan_global *globals, size_t n)
456 {
457 /* never called */
458 }
459
460 #define ASAN_LOAD_STORE(size) \
461 void __asan_load##size(unsigned long); \
462 void __asan_load##size(unsigned long addr) \
463 { \
464 kasan_shadow_check(addr, size, false, __RET_ADDR);\
465 } \
466 void __asan_load##size##_noabort(unsigned long); \
467 void __asan_load##size##_noabort(unsigned long addr) \
468 { \
469 kasan_shadow_check(addr, size, false, __RET_ADDR);\
470 } \
471 void __asan_store##size(unsigned long); \
472 void __asan_store##size(unsigned long addr) \
473 { \
474 kasan_shadow_check(addr, size, true, __RET_ADDR);\
475 } \
476 void __asan_store##size##_noabort(unsigned long); \
477 void __asan_store##size##_noabort(unsigned long addr) \
478 { \
479 kasan_shadow_check(addr, size, true, __RET_ADDR);\
480 }
481
482 ASAN_LOAD_STORE(1);
483 ASAN_LOAD_STORE(2);
484 ASAN_LOAD_STORE(4);
485 ASAN_LOAD_STORE(8);
486 ASAN_LOAD_STORE(16);
487
488 void __asan_loadN(unsigned long, size_t);
489 void __asan_loadN_noabort(unsigned long, size_t);
490 void __asan_storeN(unsigned long, size_t);
491 void __asan_storeN_noabort(unsigned long, size_t);
492 void __asan_handle_no_return(void);
493
494 void
495 __asan_loadN(unsigned long addr, size_t size)
496 {
497 kasan_shadow_check(addr, size, false, __RET_ADDR);
498 }
499
500 void
501 __asan_loadN_noabort(unsigned long addr, size_t size)
502 {
503 kasan_shadow_check(addr, size, false, __RET_ADDR);
504 }
505
506 void
507 __asan_storeN(unsigned long addr, size_t size)
508 {
509 kasan_shadow_check(addr, size, true, __RET_ADDR);
510 }
511
512 void
513 __asan_storeN_noabort(unsigned long addr, size_t size)
514 {
515 kasan_shadow_check(addr, size, true, __RET_ADDR);
516 }
517
518 void
519 __asan_handle_no_return(void)
520 {
521 /* nothing */
522 }
523
524 #define ASAN_SET_SHADOW(byte) \
525 void __asan_set_shadow_##byte(void *, size_t); \
526 void __asan_set_shadow_##byte(void *addr, size_t size) \
527 { \
528 __builtin_memset((void *)addr, 0x##byte, size); \
529 }
530
531 ASAN_SET_SHADOW(00);
532 ASAN_SET_SHADOW(f1);
533 ASAN_SET_SHADOW(f2);
534 ASAN_SET_SHADOW(f3);
535 ASAN_SET_SHADOW(f5);
536 ASAN_SET_SHADOW(f8);
537