Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/kern Improve the KASAN output, provide an error code, to...



details:   https://anonhg.NetBSD.org/src/rev/37c4438b5e1c
branches:  trunk
changeset: 449144:37c4438b5e1c
user:      maxv <maxv%NetBSD.org@localhost>
date:      Sun Feb 24 10:44:41 2019 +0000

description:
Improve the KASAN output, provide an error code, to help distinguish
classes of bugs.

diffstat:

 sys/kern/subr_asan.c |  102 ++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 72 insertions(+), 30 deletions(-)

diffs (214 lines):

diff -r 3060b1695eda -r 37c4438b5e1c sys/kern/subr_asan.c
--- a/sys/kern/subr_asan.c      Sun Feb 24 08:02:45 2019 +0000
+++ b/sys/kern/subr_asan.c      Sun Feb 24 10:44:41 2019 +0000
@@ -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 @@
 #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_ctors();
 }
 
-static void
-kasan_report(unsigned long addr, size_t size, bool write, unsigned long pc)
+static inline const char *
+kasan_code_name(uint8_t code)
 {
-       printf("ASan: Unauthorized Access In %p: Addr %p [%zu byte%s, %s]\n",
+       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,
+    uint8_t code)
+{
+       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 @@
            ((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 @@
 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 @@
        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);
        }
 }
 



Home | Main Index | Thread Index | Old Index