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);
 	}
 }
 

Reply via email to