Home | History | Annotate | Line # | Download | only in kern
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