Module Name: src Committed By: maxv Date: Sun Feb 24 10:44:41 UTC 2019
Modified Files: src/sys/kern: subr_asan.c Log Message: Improve the KASAN output, provide an error code, to help distinguish classes of bugs. To generate a diff of this commit: cvs rdiff -u -r1.4 -r1.5 src/sys/kern/subr_asan.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/subr_asan.c diff -u src/sys/kern/subr_asan.c:1.4 src/sys/kern/subr_asan.c:1.5 --- src/sys/kern/subr_asan.c:1.4 Sun Feb 24 08:02:45 2019 +++ src/sys/kern/subr_asan.c Sun Feb 24 10:44:41 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: subr_asan.c,v 1.4 2019/02/24 08:02:45 maxv Exp $ */ +/* $NetBSD: subr_asan.c,v 1.5 2019/02/24 10:44:41 maxv Exp $ */ /* * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: subr_asan.c,v 1.4 2019/02/24 08:02:45 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: subr_asan.c,v 1.5 2019/02/24 10:44:41 maxv Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -52,7 +52,7 @@ __KERNEL_RCSID(0, "$NetBSD: subr_asan.c, #include <machine/asan.h> /* Our redzone values. */ -#define KASAN_GLOBAL_REDZONE 0xFA +#define KASAN_MEMORY_FREED 0xFA #define KASAN_MEMORY_REDZONE 0xFB /* Stack redzone values. Part of the compiler ABI. */ @@ -163,12 +163,37 @@ kasan_init(void) kasan_ctors(); } +static inline const char * +kasan_code_name(uint8_t code) +{ + switch (code) { + case KASAN_MEMORY_FREED: + return "UseAfterFree"; + case KASAN_MEMORY_REDZONE: + return "RedZone"; + case 1 ... 7: + return "RedZonePartial"; + case KASAN_STACK_LEFT: + return "StackLeft"; + case KASAN_STACK_RIGHT: + return "StackRight"; + case KASAN_STACK_PARTIAL: + return "StackPartial"; + case KASAN_USE_AFTER_SCOPE: + return "UseAfterScope"; + default: + return "Unknown"; + } +} + static void -kasan_report(unsigned long addr, size_t size, bool write, unsigned long pc) +kasan_report(unsigned long addr, size_t size, bool write, unsigned long pc, + uint8_t code) { - printf("ASan: Unauthorized Access In %p: Addr %p [%zu byte%s, %s]\n", + printf("ASan: Unauthorized Access In %p: Addr %p [%zu byte%s, %s," + " %s]\n", (void *)pc, (void *)addr, size, (size > 1 ? "s" : ""), - (write ? "write" : "read")); + (write ? "write" : "read"), kasan_code_name(code)); kasan_md_unwind(); } @@ -259,69 +284,85 @@ kasan_mark(const void *addr, size_t size ((addr + size - 1) >> KASAN_SHADOW_SCALE_SHIFT) static __always_inline bool -kasan_shadow_1byte_isvalid(unsigned long addr) +kasan_shadow_1byte_isvalid(unsigned long addr, uint8_t *code) { int8_t *byte = kasan_md_addr_to_shad((void *)addr); int8_t last = (addr & KASAN_SHADOW_MASK) + 1; - return __predict_true(*byte == 0 || last <= *byte); + if (__predict_true(*byte == 0 || last <= *byte)) { + return true; + } + *code = *byte; + return false; } static __always_inline bool -kasan_shadow_2byte_isvalid(unsigned long addr) +kasan_shadow_2byte_isvalid(unsigned long addr, uint8_t *code) { int8_t *byte, last; if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 2)) { - return (kasan_shadow_1byte_isvalid(addr) && - kasan_shadow_1byte_isvalid(addr+1)); + return (kasan_shadow_1byte_isvalid(addr, code) && + kasan_shadow_1byte_isvalid(addr+1, code)); } byte = kasan_md_addr_to_shad((void *)addr); last = ((addr + 1) & KASAN_SHADOW_MASK) + 1; - return __predict_true(*byte == 0 || last <= *byte); + if (__predict_true(*byte == 0 || last <= *byte)) { + return true; + } + *code = *byte; + return false; } static __always_inline bool -kasan_shadow_4byte_isvalid(unsigned long addr) +kasan_shadow_4byte_isvalid(unsigned long addr, uint8_t *code) { int8_t *byte, last; if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 4)) { - return (kasan_shadow_2byte_isvalid(addr) && - kasan_shadow_2byte_isvalid(addr+2)); + return (kasan_shadow_2byte_isvalid(addr, code) && + kasan_shadow_2byte_isvalid(addr+2, code)); } byte = kasan_md_addr_to_shad((void *)addr); last = ((addr + 3) & KASAN_SHADOW_MASK) + 1; - return __predict_true(*byte == 0 || last <= *byte); + if (__predict_true(*byte == 0 || last <= *byte)) { + return true; + } + *code = *byte; + return false; } static __always_inline bool -kasan_shadow_8byte_isvalid(unsigned long addr) +kasan_shadow_8byte_isvalid(unsigned long addr, uint8_t *code) { int8_t *byte, last; if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 8)) { - return (kasan_shadow_4byte_isvalid(addr) && - kasan_shadow_4byte_isvalid(addr+4)); + return (kasan_shadow_4byte_isvalid(addr, code) && + kasan_shadow_4byte_isvalid(addr+4, code)); } byte = kasan_md_addr_to_shad((void *)addr); last = ((addr + 7) & KASAN_SHADOW_MASK) + 1; - return __predict_true(*byte == 0 || last <= *byte); + if (__predict_true(*byte == 0 || last <= *byte)) { + return true; + } + *code = *byte; + return false; } static __always_inline bool -kasan_shadow_Nbyte_isvalid(unsigned long addr, size_t size) +kasan_shadow_Nbyte_isvalid(unsigned long addr, size_t size, uint8_t *code) { size_t i; for (i = 0; i < size; i++) { - if (!kasan_shadow_1byte_isvalid(addr+i)) + if (!kasan_shadow_1byte_isvalid(addr+i, code)) return false; } @@ -332,6 +373,7 @@ static __always_inline void kasan_shadow_check(unsigned long addr, size_t size, bool write, unsigned long retaddr) { + uint8_t code; bool valid; if (__predict_false(!kasan_enabled)) @@ -344,27 +386,27 @@ kasan_shadow_check(unsigned long addr, s if (__builtin_constant_p(size)) { switch (size) { case 1: - valid = kasan_shadow_1byte_isvalid(addr); + valid = kasan_shadow_1byte_isvalid(addr, &code); break; case 2: - valid = kasan_shadow_2byte_isvalid(addr); + valid = kasan_shadow_2byte_isvalid(addr, &code); break; case 4: - valid = kasan_shadow_4byte_isvalid(addr); + valid = kasan_shadow_4byte_isvalid(addr, &code); break; case 8: - valid = kasan_shadow_8byte_isvalid(addr); + valid = kasan_shadow_8byte_isvalid(addr, &code); break; default: - valid = kasan_shadow_Nbyte_isvalid(addr, size); + valid = kasan_shadow_Nbyte_isvalid(addr, size, &code); break; } } else { - valid = kasan_shadow_Nbyte_isvalid(addr, size); + valid = kasan_shadow_Nbyte_isvalid(addr, size, &code); } if (__predict_false(!valid)) { - kasan_report(addr, size, write, retaddr); + kasan_report(addr, size, write, retaddr, code); } }