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