Module Name:    src
Committed By:   maxv
Date:           Wed Aug 22 12:07:43 UTC 2018

Modified Files:
        src/sys/arch/amd64/amd64: asan.c machdep.c
        src/sys/arch/amd64/conf: Makefile.amd64
        src/sys/arch/amd64/include: param.h
        src/sys/arch/x86/x86: cpu_rng.c pmap.c
        src/sys/sys: cdefs.h
        src/sys/uvm: uvm_glue.c

Log Message:
Add support for monitoring the stack with kASan. This allows us to detect
illegal memory accesses occuring there.

The compiler inlines a piece of code in each function that adds redzones
around the local variables and poisons them. The illegal accesses are then
detected using the usual kASan machinery.

The stack size is doubled, from 4 pages to 8 pages.

Several boot functions are marked with the __noasan flag, to prevent the
compiler from adding redzones in them (because we haven't yet initialized
kASan). The kasan_early_init function is called early at boot time to
quickly create the shadow for the current stack; after this is done, we
don't need __noasan anymore in the boot path.

We pass -fasan-shadow-offset=0xDFFF900000000000, because the compiler
wants to do
        shad = shadow-offset + (addr >> 3)
and we do, in kasan_addr_to_shad
        shad = KASAN_SHADOW_START + ((addr - CANONICAL_BASE) >> 3)
hence
        shad = KASAN_SHADOW_START + (addr >> 3) - (CANONICAL_BASE >> 3)
             = [KASAN_SHADOW_START - (CANONICAL_BASE >> 3)] + (addr >> 3)
implies
        shadow-offset = KASAN_SHADOW_START - (CANONICAL_BASE >> 3)
                      = 0xFFFF800000000000 - (0xFFFF800000000000 >> 3)
                      = 0xDFFF900000000000

In UVM, we add a kasan_free (that is not preceded by a kasan_alloc). We
don't add poisoned redzones ourselves, but all the functions we execute
do, so we need to manually clear the poison before freeing the stack.

With the help of Kamil for the makefile stuff.


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/amd64/amd64/asan.c
cvs rdiff -u -r1.315 -r1.316 src/sys/arch/amd64/amd64/machdep.c
cvs rdiff -u -r1.72 -r1.73 src/sys/arch/amd64/conf/Makefile.amd64
cvs rdiff -u -r1.25 -r1.26 src/sys/arch/amd64/include/param.h
cvs rdiff -u -r1.8 -r1.9 src/sys/arch/x86/x86/cpu_rng.c
cvs rdiff -u -r1.304 -r1.305 src/sys/arch/x86/x86/pmap.c
cvs rdiff -u -r1.136 -r1.137 src/sys/sys/cdefs.h
cvs rdiff -u -r1.163 -r1.164 src/sys/uvm/uvm_glue.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/arch/amd64/amd64/asan.c
diff -u src/sys/arch/amd64/amd64/asan.c:1.2 src/sys/arch/amd64/amd64/asan.c:1.3
--- src/sys/arch/amd64/amd64/asan.c:1.2	Wed Aug 22 09:11:47 2018
+++ src/sys/arch/amd64/amd64/asan.c	Wed Aug 22 12:07:42 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: asan.c,v 1.2 2018/08/22 09:11:47 maxv Exp $	*/
+/*	$NetBSD: asan.c,v 1.3 2018/08/22 12:07:42 maxv Exp $	*/
 
 /*
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: asan.c,v 1.2 2018/08/22 09:11:47 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: asan.c,v 1.3 2018/08/22 12:07:42 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -60,6 +60,7 @@ __KERNEL_RCSID(0, "$NetBSD: asan.c,v 1.2
 #define __RET_ADDR	(unsigned long)__builtin_return_address(0)
 
 void kasan_shadow_map(void *, size_t);
+void kasan_early_init(void);
 void kasan_init(void);
 
 static bool kasan_enabled __read_mostly = false;
@@ -78,25 +79,59 @@ kasan_unsupported(vaddr_t addr)
 	    addr < ((vaddr_t)PTE_BASE + NBPD_L4));
 }
 
+/* -------------------------------------------------------------------------- */
+
+static bool kasan_early __read_mostly = true;
+static uint8_t earlypages[8 * PAGE_SIZE] __aligned(PAGE_SIZE);
+static size_t earlytaken = 0;
+
+static paddr_t
+kasan_early_palloc(void)
+{
+	paddr_t ret;
+
+	KASSERT(earlytaken < 8);
+
+	ret = (paddr_t)(&earlypages[0] + earlytaken * PAGE_SIZE);
+	earlytaken++;
+
+	ret -= KERNBASE;
+
+	return ret;
+}
+
+static paddr_t
+kasan_palloc(void)
+{
+	paddr_t pa;
+
+	if (__predict_false(kasan_early))
+		pa = kasan_early_palloc();
+	else
+		pa = pmap_get_physpage();
+
+	return pa;
+}
+
 static void
 kasan_shadow_map_page(vaddr_t va)
 {
 	paddr_t pa;
 
 	if (!pmap_valid_entry(L4_BASE[pl4_i(va)])) {
-		pa = pmap_get_physpage();
+		pa = kasan_palloc();
 		L4_BASE[pl4_i(va)] = pa | PG_KW | pmap_pg_nx | PG_V;
 	}
 	if (!pmap_valid_entry(L3_BASE[pl3_i(va)])) {
-		pa = pmap_get_physpage();
+		pa = kasan_palloc();
 		L3_BASE[pl3_i(va)] = pa | PG_KW | pmap_pg_nx | PG_V;
 	}
 	if (!pmap_valid_entry(L2_BASE[pl2_i(va)])) {
-		pa = pmap_get_physpage();
+		pa = kasan_palloc();
 		L2_BASE[pl2_i(va)] = pa | PG_KW | pmap_pg_nx | PG_V;
 	}
 	if (!pmap_valid_entry(L1_BASE[pl1_i(va)])) {
-		pa = pmap_get_physpage();
+		pa = kasan_palloc();
 		L1_BASE[pl1_i(va)] = pa | PG_KW | pmap_pg_g | pmap_pg_nx | PG_V;
 	}
 }
@@ -161,6 +196,18 @@ kasan_ctors(void)
 }
 
 /*
+ * Map only the current stack. We will map the rest in kasan_init.
+ */
+void
+kasan_early_init(void)
+{
+	extern vaddr_t lwp0uarea;
+
+	kasan_shadow_map((void *)lwp0uarea, USPACE);
+	kasan_early = false;
+}
+
+/*
  * Create the shadow mapping. We don't create the 'User' area, because we
  * exclude it from the monitoring. The 'Main' area is created dynamically
  * in pmap_growkernel.

Index: src/sys/arch/amd64/amd64/machdep.c
diff -u src/sys/arch/amd64/amd64/machdep.c:1.315 src/sys/arch/amd64/amd64/machdep.c:1.316
--- src/sys/arch/amd64/amd64/machdep.c:1.315	Mon Aug 20 15:04:51 2018
+++ src/sys/arch/amd64/amd64/machdep.c	Wed Aug 22 12:07:42 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: machdep.c,v 1.315 2018/08/20 15:04:51 maxv Exp $	*/
+/*	$NetBSD: machdep.c,v 1.316 2018/08/22 12:07:42 maxv Exp $	*/
 
 /*
  * Copyright (c) 1996, 1997, 1998, 2000, 2006, 2007, 2008, 2011
@@ -110,7 +110,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.315 2018/08/20 15:04:51 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.316 2018/08/22 12:07:42 maxv Exp $");
 
 #include "opt_modular.h"
 #include "opt_user_ldt.h"
@@ -1543,7 +1543,7 @@ init_x86_64_ksyms(void)
 #endif
 }
 
-void
+void __noasan
 init_bootspace(void)
 {
 	extern char __rodata_start;
@@ -1591,7 +1591,8 @@ init_bootspace(void)
 	bootspace.emodule = KERNBASE + NKL2_KIMG_ENTRIES * NBPD_L2;
 }
 
-static void init_pte(void)
+static void __noasan
+init_pte(void)
 {
 #ifndef XEN
 	extern uint32_t nox_flag;
@@ -1606,7 +1607,7 @@ static void init_pte(void)
 	normal_pdes[2] = L4_BASE;
 }
 
-void
+void __noasan
 init_slotspace(void)
 {
 	vaddr_t slotspace_rand(int, size_t, size_t);
@@ -1690,7 +1691,7 @@ init_slotspace(void)
 #endif
 }
 
-void
+void __noasan
 init_x86_64(paddr_t first_avail)
 {
 	extern void consinit(void);
@@ -1713,6 +1714,11 @@ init_x86_64(paddr_t first_avail)
 
 	init_pte();
 
+#ifdef KASAN
+	void kasan_early_init(void);
+	kasan_early_init();
+#endif
+
 	uvm_lwp_setuarea(&lwp0, lwp0uarea);
 
 	cpu_probe(&cpu_info_primary);

Index: src/sys/arch/amd64/conf/Makefile.amd64
diff -u src/sys/arch/amd64/conf/Makefile.amd64:1.72 src/sys/arch/amd64/conf/Makefile.amd64:1.73
--- src/sys/arch/amd64/conf/Makefile.amd64:1.72	Mon Aug 20 15:04:51 2018
+++ src/sys/arch/amd64/conf/Makefile.amd64	Wed Aug 22 12:07:42 2018
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile.amd64,v 1.72 2018/08/20 15:04:51 maxv Exp $
+#	$NetBSD: Makefile.amd64,v 1.73 2018/08/22 12:07:42 maxv Exp $
 
 # Makefile for NetBSD
 #
@@ -50,8 +50,13 @@ CFLAGS+=      -mindirect-branch-register
 .endif
 
 .if ${KASAN:U0} > 0 && ${HAVE_GCC:U0} > 0
-CFLAGS+=	-fsanitize=kernel-address --param asan-globals=1
-COPTS.asan.c+=	-fno-sanitize=kernel-address
+KASANFLAGS=	-fsanitize=kernel-address \
+		--param asan-globals=1 --param asan-stack=1 \
+		-fasan-shadow-offset=0xDFFF900000000000
+.for f in asan.c
+KASANFLAGS.${f}=	# empty
+.endfor
+CFLAGS+=	${KASANFLAGS.${.IMPSRC:T}:U${KASANFLAGS}}
 .endif
 
 ##

Index: src/sys/arch/amd64/include/param.h
diff -u src/sys/arch/amd64/include/param.h:1.25 src/sys/arch/amd64/include/param.h:1.26
--- src/sys/arch/amd64/include/param.h:1.25	Fri Mar 16 08:21:56 2018
+++ src/sys/arch/amd64/include/param.h	Wed Aug 22 12:07:43 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: param.h,v 1.25 2018/03/16 08:21:56 maxv Exp $	*/
+/*	$NetBSD: param.h,v 1.26 2018/08/22 12:07:43 maxv Exp $	*/
 
 #ifdef __x86_64__
 
@@ -9,6 +9,9 @@
 
 #ifdef _KERNEL
 #include <machine/cpu.h>
+#if defined(_KERNEL_OPT)
+#include "opt_kasan.h"
+#endif
 #endif
 
 #define	_MACHINE	amd64
@@ -57,7 +60,10 @@
 
 #define	SSIZE		1		/* initial stack size/NBPG */
 #define	SINCR		1		/* increment of stack/NBPG */
-#ifdef DIAGNOSTIC
+
+#ifdef KASAN
+#define	UPAGES		8
+#elif defined(DIAGNOSTIC)
 #define	UPAGES		5		/* pages of u-area (1 for redzone) */
 #else
 #define	UPAGES		4		/* pages of u-area */

Index: src/sys/arch/x86/x86/cpu_rng.c
diff -u src/sys/arch/x86/x86/cpu_rng.c:1.8 src/sys/arch/x86/x86/cpu_rng.c:1.9
--- src/sys/arch/x86/x86/cpu_rng.c:1.8	Sat Jul 21 16:21:27 2018
+++ src/sys/arch/x86/x86/cpu_rng.c	Wed Aug 22 12:07:43 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu_rng.c,v 1.8 2018/07/21 16:21:27 maxv Exp $ */
+/* $NetBSD: cpu_rng.c,v 1.9 2018/08/22 12:07:43 maxv Exp $ */
 
 /*-
  * Copyright (c) 2015 The NetBSD Foundation, Inc.
@@ -203,7 +203,7 @@ static uint64_t earlyrng_state;
  * Small PRNG, that can be used very early. The only requirement is that
  * cpu_probe got called before.
  */
-void
+void __noasan
 cpu_earlyrng(void *out, size_t sz)
 {
 	uint8_t digest[SHA512_DIGEST_LENGTH];

Index: src/sys/arch/x86/x86/pmap.c
diff -u src/sys/arch/x86/x86/pmap.c:1.304 src/sys/arch/x86/x86/pmap.c:1.305
--- src/sys/arch/x86/x86/pmap.c:1.304	Mon Aug 20 15:04:52 2018
+++ src/sys/arch/x86/x86/pmap.c	Wed Aug 22 12:07:43 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: pmap.c,v 1.304 2018/08/20 15:04:52 maxv Exp $	*/
+/*	$NetBSD: pmap.c,v 1.305 2018/08/22 12:07:43 maxv Exp $	*/
 
 /*
  * Copyright (c) 2008, 2010, 2016, 2017 The NetBSD Foundation, Inc.
@@ -157,7 +157,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.304 2018/08/20 15:04:52 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.305 2018/08/22 12:07:43 maxv Exp $");
 
 #include "opt_user_ldt.h"
 #include "opt_lockdebug.h"
@@ -1405,7 +1405,7 @@ vaddr_t slotspace_rand(int, size_t, size
  * randomly select one hole, and then randomly select an area within that hole.
  * Finally we update the associated entry in the slotspace structure.
  */
-vaddr_t
+vaddr_t __noasan
 slotspace_rand(int type, size_t sz, size_t align)
 {
 	struct {

Index: src/sys/sys/cdefs.h
diff -u src/sys/sys/cdefs.h:1.136 src/sys/sys/cdefs.h:1.137
--- src/sys/sys/cdefs.h:1.136	Sun Aug 12 10:43:04 2018
+++ src/sys/sys/cdefs.h	Wed Aug 22 12:07:43 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: cdefs.h,v 1.136 2018/08/12 10:43:04 skrll Exp $	*/
+/*	$NetBSD: cdefs.h,v 1.137 2018/08/22 12:07:43 maxv Exp $	*/
 
 /* * Copyright (c) 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -38,6 +38,7 @@
 
 #ifdef _KERNEL_OPT
 #include "opt_diagnostic.h"
+#include "opt_kasan.h"
 #endif
 
 /*
@@ -306,6 +307,14 @@
 #define	__unreachable()	do {} while (/*CONSTCOND*/0)
 #endif
 
+#if defined(_KERNEL)
+#if __GNUC_PREREQ__(4, 9) && defined(KASAN)
+#define	__noasan	__attribute__((no_sanitize_address))
+#else
+#define	__noasan	/* nothing */
+#endif
+#endif
+
 /*
  * To be used when an empty body is required like:
  *

Index: src/sys/uvm/uvm_glue.c
diff -u src/sys/uvm/uvm_glue.c:1.163 src/sys/uvm/uvm_glue.c:1.164
--- src/sys/uvm/uvm_glue.c:1.163	Sun May 22 09:10:37 2016
+++ src/sys/uvm/uvm_glue.c	Wed Aug 22 12:07:43 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: uvm_glue.c,v 1.163 2016/05/22 09:10:37 maxv Exp $	*/
+/*	$NetBSD: uvm_glue.c,v 1.164 2018/08/22 12:07:43 maxv Exp $	*/
 
 /*
  * Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -62,11 +62,12 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_glue.c,v 1.163 2016/05/22 09:10:37 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_glue.c,v 1.164 2018/08/22 12:07:43 maxv Exp $");
 
 #include "opt_kgdb.h"
 #include "opt_kstack.h"
 #include "opt_uvmhist.h"
+#include "opt_kasan.h"
 
 /*
  * uvm_glue.c: glue functions
@@ -83,6 +84,7 @@ __KERNEL_RCSID(0, "$NetBSD: uvm_glue.c,v
 #include <sys/cpu.h>
 #include <sys/atomic.h>
 #include <sys/lwp.h>
+#include <sys/asan.h>
 
 #include <uvm/uvm.h>
 
@@ -384,6 +386,7 @@ void
 uvm_uarea_free(vaddr_t uaddr)
 {
 
+	kasan_free((void *)uaddr, USPACE);
 	pool_cache_put(uvm_uarea_cache, (void *)uaddr);
 }
 
@@ -391,6 +394,7 @@ void
 uvm_uarea_system_free(vaddr_t uaddr)
 {
 
+	kasan_free((void *)uaddr, USPACE);
 	pool_cache_put(uvm_uarea_system_cache, (void *)uaddr);
 }
 

Reply via email to