Home | History | Annotate | Line # | Download | only in kern
subr_asan.c revision 1.5
      1 /*	$NetBSD: subr_asan.c,v 1.5 2019/02/24 10:44:41 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.5 2019/02/24 10:44:41 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_MEMORY_FREED	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 inline const char *
    167 kasan_code_name(uint8_t code)
    168 {
    169 	switch (code) {
    170 	case KASAN_MEMORY_FREED:
    171 		return "UseAfterFree";
    172 	case KASAN_MEMORY_REDZONE:
    173 		return "RedZone";
    174 	case 1 ... 7:
    175 		return "RedZonePartial";
    176 	case KASAN_STACK_LEFT:
    177 		return "StackLeft";
    178 	case KASAN_STACK_RIGHT:
    179 		return "StackRight";
    180 	case KASAN_STACK_PARTIAL:
    181 		return "StackPartial";
    182 	case KASAN_USE_AFTER_SCOPE:
    183 		return "UseAfterScope";
    184 	default:
    185 		return "Unknown";
    186 	}
    187 }
    188 
    189 static void
    190 kasan_report(unsigned long addr, size_t size, bool write, unsigned long pc,
    191     uint8_t code)
    192 {
    193 	printf("ASan: Unauthorized Access In %p: Addr %p [%zu byte%s, %s,"
    194 	    " %s]\n",
    195 	    (void *)pc, (void *)addr, size, (size > 1 ? "s" : ""),
    196 	    (write ? "write" : "read"), kasan_code_name(code));
    197 	kasan_md_unwind();
    198 }
    199 
    200 static __always_inline void
    201 kasan_shadow_1byte_markvalid(unsigned long addr)
    202 {
    203 	int8_t *byte = kasan_md_addr_to_shad((void *)addr);
    204 	int8_t last = (addr & KASAN_SHADOW_MASK) + 1;
    205 
    206 	*byte = last;
    207 }
    208 
    209 static __always_inline void
    210 kasan_shadow_Nbyte_markvalid(const void *addr, size_t size)
    211 {
    212 	size_t i;
    213 
    214 	for (i = 0; i < size; i++) {
    215 		kasan_shadow_1byte_markvalid((unsigned long)addr+i);
    216 	}
    217 }
    218 
    219 static __always_inline void
    220 kasan_shadow_Nbyte_fill(const void *addr, size_t size, uint8_t val)
    221 {
    222 	void *shad;
    223 
    224 	if (__predict_false(size == 0))
    225 		return;
    226 	if (__predict_false(kasan_md_unsupported((vaddr_t)addr)))
    227 		return;
    228 
    229 	KASSERT((vaddr_t)addr % KASAN_SHADOW_SCALE_SIZE == 0);
    230 	KASSERT(size % KASAN_SHADOW_SCALE_SIZE == 0);
    231 
    232 	shad = (void *)kasan_md_addr_to_shad(addr);
    233 	size = size >> KASAN_SHADOW_SCALE_SHIFT;
    234 
    235 	__builtin_memset(shad, val, size);
    236 }
    237 
    238 void
    239 kasan_add_redzone(size_t *size)
    240 {
    241 	*size = roundup(*size, KASAN_SHADOW_SCALE_SIZE);
    242 	*size += KASAN_SHADOW_SCALE_SIZE;
    243 }
    244 
    245 static void
    246 kasan_markmem(const void *addr, size_t size, bool valid)
    247 {
    248 	KASSERT((vaddr_t)addr % KASAN_SHADOW_SCALE_SIZE == 0);
    249 	if (valid) {
    250 		kasan_shadow_Nbyte_markvalid(addr, size);
    251 	} else {
    252 		kasan_shadow_Nbyte_fill(addr, size, KASAN_MEMORY_REDZONE);
    253 	}
    254 }
    255 
    256 void
    257 kasan_softint(struct lwp *l)
    258 {
    259 	const void *stk = (const void *)uvm_lwp_getuarea(l);
    260 
    261 	kasan_shadow_Nbyte_fill(stk, USPACE, 0);
    262 }
    263 
    264 /*
    265  * In an area of size 'sz_with_redz', mark the 'size' first bytes as valid,
    266  * and the rest as invalid. There are generally two use cases:
    267  *
    268  *  o kasan_mark(addr, origsize, size), with origsize < size. This marks the
    269  *    redzone at the end of the buffer as invalid.
    270  *
    271  *  o kasan_mark(addr, size, size). This marks the entire buffer as valid.
    272  */
    273 void
    274 kasan_mark(const void *addr, size_t size, size_t sz_with_redz)
    275 {
    276 	kasan_markmem(addr, sz_with_redz, false);
    277 	kasan_markmem(addr, size, true);
    278 }
    279 
    280 /* -------------------------------------------------------------------------- */
    281 
    282 #define ADDR_CROSSES_SCALE_BOUNDARY(addr, size) 		\
    283 	(addr >> KASAN_SHADOW_SCALE_SHIFT) !=			\
    284 	    ((addr + size - 1) >> KASAN_SHADOW_SCALE_SHIFT)
    285 
    286 static __always_inline bool
    287 kasan_shadow_1byte_isvalid(unsigned long addr, uint8_t *code)
    288 {
    289 	int8_t *byte = kasan_md_addr_to_shad((void *)addr);
    290 	int8_t last = (addr & KASAN_SHADOW_MASK) + 1;
    291 
    292 	if (__predict_true(*byte == 0 || last <= *byte)) {
    293 		return true;
    294 	}
    295 	*code = *byte;
    296 	return false;
    297 }
    298 
    299 static __always_inline bool
    300 kasan_shadow_2byte_isvalid(unsigned long addr, uint8_t *code)
    301 {
    302 	int8_t *byte, last;
    303 
    304 	if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 2)) {
    305 		return (kasan_shadow_1byte_isvalid(addr, code) &&
    306 		    kasan_shadow_1byte_isvalid(addr+1, code));
    307 	}
    308 
    309 	byte = kasan_md_addr_to_shad((void *)addr);
    310 	last = ((addr + 1) & KASAN_SHADOW_MASK) + 1;
    311 
    312 	if (__predict_true(*byte == 0 || last <= *byte)) {
    313 		return true;
    314 	}
    315 	*code = *byte;
    316 	return false;
    317 }
    318 
    319 static __always_inline bool
    320 kasan_shadow_4byte_isvalid(unsigned long addr, uint8_t *code)
    321 {
    322 	int8_t *byte, last;
    323 
    324 	if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 4)) {
    325 		return (kasan_shadow_2byte_isvalid(addr, code) &&
    326 		    kasan_shadow_2byte_isvalid(addr+2, code));
    327 	}
    328 
    329 	byte = kasan_md_addr_to_shad((void *)addr);
    330 	last = ((addr + 3) & KASAN_SHADOW_MASK) + 1;
    331 
    332 	if (__predict_true(*byte == 0 || last <= *byte)) {
    333 		return true;
    334 	}
    335 	*code = *byte;
    336 	return false;
    337 }
    338 
    339 static __always_inline bool
    340 kasan_shadow_8byte_isvalid(unsigned long addr, uint8_t *code)
    341 {
    342 	int8_t *byte, last;
    343 
    344 	if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 8)) {
    345 		return (kasan_shadow_4byte_isvalid(addr, code) &&
    346 		    kasan_shadow_4byte_isvalid(addr+4, code));
    347 	}
    348 
    349 	byte = kasan_md_addr_to_shad((void *)addr);
    350 	last = ((addr + 7) & KASAN_SHADOW_MASK) + 1;
    351 
    352 	if (__predict_true(*byte == 0 || last <= *byte)) {
    353 		return true;
    354 	}
    355 	*code = *byte;
    356 	return false;
    357 }
    358 
    359 static __always_inline bool
    360 kasan_shadow_Nbyte_isvalid(unsigned long addr, size_t size, uint8_t *code)
    361 {
    362 	size_t i;
    363 
    364 	for (i = 0; i < size; i++) {
    365 		if (!kasan_shadow_1byte_isvalid(addr+i, code))
    366 			return false;
    367 	}
    368 
    369 	return true;
    370 }
    371 
    372 static __always_inline void
    373 kasan_shadow_check(unsigned long addr, size_t size, bool write,
    374     unsigned long retaddr)
    375 {
    376 	uint8_t code;
    377 	bool valid;
    378 
    379 	if (__predict_false(!kasan_enabled))
    380 		return;
    381 	if (__predict_false(size == 0))
    382 		return;
    383 	if (__predict_false(kasan_md_unsupported(addr)))
    384 		return;
    385 
    386 	if (__builtin_constant_p(size)) {
    387 		switch (size) {
    388 		case 1:
    389 			valid = kasan_shadow_1byte_isvalid(addr, &code);
    390 			break;
    391 		case 2:
    392 			valid = kasan_shadow_2byte_isvalid(addr, &code);
    393 			break;
    394 		case 4:
    395 			valid = kasan_shadow_4byte_isvalid(addr, &code);
    396 			break;
    397 		case 8:
    398 			valid = kasan_shadow_8byte_isvalid(addr, &code);
    399 			break;
    400 		default:
    401 			valid = kasan_shadow_Nbyte_isvalid(addr, size, &code);
    402 			break;
    403 		}
    404 	} else {
    405 		valid = kasan_shadow_Nbyte_isvalid(addr, size, &code);
    406 	}
    407 
    408 	if (__predict_false(!valid)) {
    409 		kasan_report(addr, size, write, retaddr, code);
    410 	}
    411 }
    412 
    413 /* -------------------------------------------------------------------------- */
    414 
    415 void *
    416 kasan_memcpy(void *dst, const void *src, size_t len)
    417 {
    418 	kasan_shadow_check((unsigned long)src, len, false, __RET_ADDR);
    419 	kasan_shadow_check((unsigned long)dst, len, true, __RET_ADDR);
    420 	return __builtin_memcpy(dst, src, len);
    421 }
    422 
    423 int
    424 kasan_memcmp(const void *b1, const void *b2, size_t len)
    425 {
    426 	kasan_shadow_check((unsigned long)b1, len, false, __RET_ADDR);
    427 	kasan_shadow_check((unsigned long)b2, len, false, __RET_ADDR);
    428 	return __builtin_memcmp(b1, b2, len);
    429 }
    430 
    431 void *
    432 kasan_memset(void *b, int c, size_t len)
    433 {
    434 	kasan_shadow_check((unsigned long)b, len, true, __RET_ADDR);
    435 	return __builtin_memset(b, c, len);
    436 }
    437 
    438 char *
    439 kasan_strcpy(char *dst, const char *src)
    440 {
    441 	char *save = dst;
    442 
    443 	while (1) {
    444 		kasan_shadow_check((unsigned long)src, 1, false, __RET_ADDR);
    445 		kasan_shadow_check((unsigned long)dst, 1, true, __RET_ADDR);
    446 		*dst = *src;
    447 		if (*src == '\0')
    448 			break;
    449 		src++, dst++;
    450 	}
    451 
    452 	return save;
    453 }
    454 
    455 int
    456 kasan_strcmp(const char *s1, const char *s2)
    457 {
    458 	while (1) {
    459 		kasan_shadow_check((unsigned long)s1, 1, false, __RET_ADDR);
    460 		kasan_shadow_check((unsigned long)s2, 1, false, __RET_ADDR);
    461 		if (*s1 != *s2)
    462 			break;
    463 		if (*s1 == '\0')
    464 			return 0;
    465 		s1++, s2++;
    466 	}
    467 
    468 	return (*(const unsigned char *)s1 - *(const unsigned char *)s2);
    469 }
    470 
    471 size_t
    472 kasan_strlen(const char *str)
    473 {
    474 	const char *s;
    475 
    476 	s = str;
    477 	while (1) {
    478 		kasan_shadow_check((unsigned long)s, 1, false, __RET_ADDR);
    479 		if (*s == '\0')
    480 			break;
    481 		s++;
    482 	}
    483 
    484 	return (s - str);
    485 }
    486 
    487 /* -------------------------------------------------------------------------- */
    488 
    489 void __asan_register_globals(struct __asan_global *, size_t);
    490 void __asan_unregister_globals(struct __asan_global *, size_t);
    491 
    492 void
    493 __asan_register_globals(struct __asan_global *globals, size_t n)
    494 {
    495 	size_t i;
    496 
    497 	for (i = 0; i < n; i++) {
    498 		kasan_mark(globals[i].beg, globals[i].size,
    499 		    globals[i].size_with_redzone);
    500 	}
    501 }
    502 
    503 void
    504 __asan_unregister_globals(struct __asan_global *globals, size_t n)
    505 {
    506 	/* never called */
    507 }
    508 
    509 #define ASAN_LOAD_STORE(size)					\
    510 	void __asan_load##size(unsigned long);			\
    511 	void __asan_load##size(unsigned long addr)		\
    512 	{							\
    513 		kasan_shadow_check(addr, size, false, __RET_ADDR);\
    514 	} 							\
    515 	void __asan_load##size##_noabort(unsigned long);	\
    516 	void __asan_load##size##_noabort(unsigned long addr)	\
    517 	{							\
    518 		kasan_shadow_check(addr, size, false, __RET_ADDR);\
    519 	}							\
    520 	void __asan_store##size(unsigned long);			\
    521 	void __asan_store##size(unsigned long addr)		\
    522 	{							\
    523 		kasan_shadow_check(addr, size, true, __RET_ADDR);\
    524 	}							\
    525 	void __asan_store##size##_noabort(unsigned long);	\
    526 	void __asan_store##size##_noabort(unsigned long addr)	\
    527 	{							\
    528 		kasan_shadow_check(addr, size, true, __RET_ADDR);\
    529 	}
    530 
    531 ASAN_LOAD_STORE(1);
    532 ASAN_LOAD_STORE(2);
    533 ASAN_LOAD_STORE(4);
    534 ASAN_LOAD_STORE(8);
    535 ASAN_LOAD_STORE(16);
    536 
    537 void __asan_loadN(unsigned long, size_t);
    538 void __asan_loadN_noabort(unsigned long, size_t);
    539 void __asan_storeN(unsigned long, size_t);
    540 void __asan_storeN_noabort(unsigned long, size_t);
    541 void __asan_handle_no_return(void);
    542 
    543 void
    544 __asan_loadN(unsigned long addr, size_t size)
    545 {
    546 	kasan_shadow_check(addr, size, false, __RET_ADDR);
    547 }
    548 
    549 void
    550 __asan_loadN_noabort(unsigned long addr, size_t size)
    551 {
    552 	kasan_shadow_check(addr, size, false, __RET_ADDR);
    553 }
    554 
    555 void
    556 __asan_storeN(unsigned long addr, size_t size)
    557 {
    558 	kasan_shadow_check(addr, size, true, __RET_ADDR);
    559 }
    560 
    561 void
    562 __asan_storeN_noabort(unsigned long addr, size_t size)
    563 {
    564 	kasan_shadow_check(addr, size, true, __RET_ADDR);
    565 }
    566 
    567 void
    568 __asan_handle_no_return(void)
    569 {
    570 	/* nothing */
    571 }
    572 
    573 #define ASAN_SET_SHADOW(byte) \
    574 	void __asan_set_shadow_##byte(void *, size_t);			\
    575 	void __asan_set_shadow_##byte(void *addr, size_t size)		\
    576 	{								\
    577 		__builtin_memset((void *)addr, 0x##byte, size);		\
    578 	}
    579 
    580 ASAN_SET_SHADOW(00);
    581 ASAN_SET_SHADOW(f1);
    582 ASAN_SET_SHADOW(f2);
    583 ASAN_SET_SHADOW(f3);
    584 ASAN_SET_SHADOW(f5);
    585 ASAN_SET_SHADOW(f8);
    586 
    587 void __asan_poison_stack_memory(const void *, size_t);
    588 void __asan_unpoison_stack_memory(const void *, size_t);
    589 
    590 void __asan_poison_stack_memory(const void *addr, size_t size)
    591 {
    592 	size = roundup(size, KASAN_SHADOW_SCALE_SIZE);
    593 	kasan_shadow_Nbyte_fill(addr, size, KASAN_USE_AFTER_SCOPE);
    594 }
    595 
    596 void __asan_unpoison_stack_memory(const void *addr, size_t size)
    597 {
    598 	kasan_shadow_Nbyte_markvalid(addr, size);
    599 }
    600