xref: /netbsd-src/sys/kern/subr_asan.c (revision deb6f0161a9109e7de9b519dc8dfb9478668dcdd)
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