Module Name: src
Committed By: maxv
Date: Wed Oct 31 06:26:26 UTC 2018
Modified Files:
src/sys/arch/amd64/amd64: machdep.c
src/sys/arch/amd64/conf: Makefile.amd64 files.amd64
src/sys/arch/amd64/include: Makefile
src/sys/arch/x86/x86: pmap.c
src/sys/kern: files.kern
src/sys/sys: asan.h
Added Files:
src/sys/arch/amd64/include: asan.h
src/sys/kern: subr_asan.c
Removed Files:
src/sys/arch/amd64/amd64: asan.c
Log Message:
Move the MI parts of KASAN into kern/subr_asan.c. This file includes
machine/asan.h, which contains the MD functions. We use an include rather
than a plain C file, because we want GCC to optimize/inline some functions
into one single block.
The amd64 MD parts of KASAN are moved accordingly.
The naming convention we use is:
kasan_*
a generic kasan object, declared in subr_asan.c
kasan_md_*
an MD kasan object, declared in machine/asan.h, and used
in subr_asan.c
__md_*
an MD object, declared in machine/asan.h, and not used
outside
Overall this makes it easier to add KASAN support on more architectures.
Discussed with several people.
To generate a diff of this commit:
cvs rdiff -u -r1.10 -r0 src/sys/arch/amd64/amd64/asan.c
cvs rdiff -u -r1.319 -r1.320 src/sys/arch/amd64/amd64/machdep.c
cvs rdiff -u -r1.74 -r1.75 src/sys/arch/amd64/conf/Makefile.amd64
cvs rdiff -u -r1.106 -r1.107 src/sys/arch/amd64/conf/files.amd64
cvs rdiff -u -r1.20 -r1.21 src/sys/arch/amd64/include/Makefile
cvs rdiff -u -r0 -r1.1 src/sys/arch/amd64/include/asan.h
cvs rdiff -u -r1.308 -r1.309 src/sys/arch/x86/x86/pmap.c
cvs rdiff -u -r1.23 -r1.24 src/sys/kern/files.kern
cvs rdiff -u -r0 -r1.1 src/sys/kern/subr_asan.c
cvs rdiff -u -r1.7 -r1.8 src/sys/sys/asan.h
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/machdep.c
diff -u src/sys/arch/amd64/amd64/machdep.c:1.319 src/sys/arch/amd64/amd64/machdep.c:1.320
--- src/sys/arch/amd64/amd64/machdep.c:1.319 Sun Sep 23 00:59:59 2018
+++ src/sys/arch/amd64/amd64/machdep.c Wed Oct 31 06:26:25 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.319 2018/09/23 00:59:59 cherry Exp $ */
+/* $NetBSD: machdep.c,v 1.320 2018/10/31 06:26:25 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.319 2018/09/23 00:59:59 cherry Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.320 2018/10/31 06:26:25 maxv Exp $");
#include "opt_modular.h"
#include "opt_user_ldt.h"
@@ -152,6 +152,7 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v
#include <sys/device.h>
#include <sys/lwp.h>
#include <sys/proc.h>
+#include <sys/asan.h>
#ifdef KGDB
#include <sys/kgdb.h>
@@ -1683,8 +1684,7 @@ init_x86_64(paddr_t first_avail)
init_pte();
#ifdef KASAN
- void kasan_early_init(void);
- kasan_early_init();
+ kasan_early_init((void *)lwp0uarea);
#endif
uvm_lwp_setuarea(&lwp0, lwp0uarea);
@@ -1766,7 +1766,6 @@ init_x86_64(paddr_t first_avail)
init_x86_msgbuf();
#ifdef KASAN
- void kasan_init(void);
kasan_init();
#endif
Index: src/sys/arch/amd64/conf/Makefile.amd64
diff -u src/sys/arch/amd64/conf/Makefile.amd64:1.74 src/sys/arch/amd64/conf/Makefile.amd64:1.75
--- src/sys/arch/amd64/conf/Makefile.amd64:1.74 Sat Sep 22 12:24:01 2018
+++ src/sys/arch/amd64/conf/Makefile.amd64 Wed Oct 31 06:26:25 2018
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile.amd64,v 1.74 2018/09/22 12:24:01 rin Exp $
+# $NetBSD: Makefile.amd64,v 1.75 2018/10/31 06:26:25 maxv Exp $
# Makefile for NetBSD
#
@@ -53,7 +53,7 @@ CFLAGS+= -mindirect-branch-register
KASANFLAGS= -fsanitize=kernel-address \
--param asan-globals=1 --param asan-stack=1 \
-fasan-shadow-offset=0xDFFF900000000000
-.for f in asan.c
+.for f in subr_asan.c
KASANFLAGS.${f}= # empty
.endfor
CFLAGS+= ${KASANFLAGS.${.IMPSRC:T}:U${KASANFLAGS}}
Index: src/sys/arch/amd64/conf/files.amd64
diff -u src/sys/arch/amd64/conf/files.amd64:1.106 src/sys/arch/amd64/conf/files.amd64:1.107
--- src/sys/arch/amd64/conf/files.amd64:1.106 Mon Aug 20 15:04:51 2018
+++ src/sys/arch/amd64/conf/files.amd64 Wed Oct 31 06:26:25 2018
@@ -1,4 +1,4 @@
-# $NetBSD: files.amd64,v 1.106 2018/08/20 15:04:51 maxv Exp $
+# $NetBSD: files.amd64,v 1.107 2018/10/31 06:26:25 maxv Exp $
#
# new style config file for amd64 architecture
#
@@ -39,7 +39,6 @@ file arch/amd64/amd64/spl.S machdep
file arch/amd64/amd64/amd64func.S machdep
file arch/amd64/amd64/amd64_trap.S machdep
-file arch/amd64/amd64/asan.c kasan
file arch/amd64/amd64/autoconf.c machdep
file arch/amd64/amd64/busfunc.S machdep
file arch/amd64/amd64/cpu_in_cksum.S (inet | inet6) & cpu_in_cksum
Index: src/sys/arch/amd64/include/Makefile
diff -u src/sys/arch/amd64/include/Makefile:1.20 src/sys/arch/amd64/include/Makefile:1.21
--- src/sys/arch/amd64/include/Makefile:1.20 Thu Jul 12 10:46:41 2018
+++ src/sys/arch/amd64/include/Makefile Wed Oct 31 06:26:26 2018
@@ -1,8 +1,8 @@
-# $NetBSD: Makefile,v 1.20 2018/07/12 10:46:41 maxv Exp $
+# $NetBSD: Makefile,v 1.21 2018/10/31 06:26:26 maxv Exp $
INCSDIR= /usr/include/amd64
-INCS= ansi.h aout_machdep.h asm.h \
+INCS= ansi.h aout_machdep.h asan.h asm.h \
bootinfo.h bswap.h byte_swap.h \
cdefs.h cpu.h cpu_rng.h\
disklabel.h \
Index: src/sys/arch/x86/x86/pmap.c
diff -u src/sys/arch/x86/x86/pmap.c:1.308 src/sys/arch/x86/x86/pmap.c:1.309
--- src/sys/arch/x86/x86/pmap.c:1.308 Sat Sep 29 13:19:38 2018
+++ src/sys/arch/x86/x86/pmap.c Wed Oct 31 06:26:26 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.308 2018/09/29 13:19:38 cherry Exp $ */
+/* $NetBSD: pmap.c,v 1.309 2018/10/31 06:26:26 maxv Exp $ */
/*
* Copyright (c) 2008, 2010, 2016, 2017 The NetBSD Foundation, Inc.
@@ -130,7 +130,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.308 2018/09/29 13:19:38 cherry Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.309 2018/10/31 06:26:26 maxv Exp $");
#include "opt_user_ldt.h"
#include "opt_lockdebug.h"
@@ -149,6 +149,7 @@ __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.3
#include <sys/intr.h>
#include <sys/xcall.h>
#include <sys/kcore.h>
+#include <sys/asan.h>
#include <uvm/uvm.h>
#include <uvm/pmap/pmap_pvt.h>
@@ -4494,7 +4495,6 @@ pmap_growkernel(vaddr_t maxkvaddr)
#endif
#ifdef KASAN
- void kasan_shadow_map(void *, size_t);
kasan_shadow_map((void *)pmap_maxkvaddr,
(size_t)(maxkvaddr - pmap_maxkvaddr));
#endif
Index: src/sys/kern/files.kern
diff -u src/sys/kern/files.kern:1.23 src/sys/kern/files.kern:1.24
--- src/sys/kern/files.kern:1.23 Fri Sep 14 01:55:19 2018
+++ src/sys/kern/files.kern Wed Oct 31 06:26:26 2018
@@ -1,4 +1,4 @@
-# $NetBSD: files.kern,v 1.23 2018/09/14 01:55:19 mrg Exp $
+# $NetBSD: files.kern,v 1.24 2018/10/31 06:26:26 maxv Exp $
#
# kernel sources
@@ -95,6 +95,7 @@ file kern/kern_uuid.c kern
file kern/kgdb_stub.c kgdb
file kern/sched_4bsd.c sched_4bsd
file kern/sched_m2.c sched_m2
+file kern/subr_asan.c kasan
file kern/subr_autoconf.c kern
file kern/subr_blist.c vmswap
file kern/subr_bufq.c kern
Index: src/sys/sys/asan.h
diff -u src/sys/sys/asan.h:1.7 src/sys/sys/asan.h:1.8
--- src/sys/sys/asan.h:1.7 Wed Aug 22 14:11:26 2018
+++ src/sys/sys/asan.h Wed Oct 31 06:26:26 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: asan.h,v 1.7 2018/08/22 14:11:26 christos Exp $ */
+/* $NetBSD: asan.h,v 1.8 2018/10/31 06:26:26 maxv Exp $ */
/*
* Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -39,6 +39,11 @@
#include <sys/types.h>
#ifdef KASAN
+void kasan_shadow_map(void *, size_t);
+void kasan_early_init(void *);
+void kasan_init(void);
+void kasan_softint(struct lwp *);
+
void kasan_add_redzone(size_t *);
void kasan_alloc(const void *, size_t, size_t);
void kasan_free(const void *, size_t);
Added files:
Index: src/sys/arch/amd64/include/asan.h
diff -u /dev/null src/sys/arch/amd64/include/asan.h:1.1
--- /dev/null Wed Oct 31 06:26:26 2018
+++ src/sys/arch/amd64/include/asan.h Wed Oct 31 06:26:26 2018
@@ -0,0 +1,221 @@
+/* $NetBSD: asan.h,v 1.1 2018/10/31 06:26:26 maxv Exp $ */
+
+/*
+ * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Maxime Villard.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/ksyms.h>
+
+#include <amd64/pmap.h>
+#include <amd64/vmparam.h>
+
+#ifdef __HAVE_PCPU_AREA
+#error "PCPU area not allowed with KASAN"
+#endif
+#ifdef __HAVE_DIRECT_MAP
+#error "DMAP not allowed with KASAN"
+#endif
+
+#define __MD_VIRTUAL_SHIFT 47 /* 48bit address space, cut half */
+#define __MD_CANONICAL_BASE 0xFFFF800000000000
+
+#define __MD_SHADOW_SIZE (1ULL << (__MD_VIRTUAL_SHIFT - KASAN_SHADOW_SCALE_SHIFT))
+#define KASAN_MD_SHADOW_START (VA_SIGN_NEG((L4_SLOT_KASAN * NBPD_L4)))
+#define KASAN_MD_SHADOW_END (KASAN_MD_SHADOW_START + __MD_SHADOW_SIZE)
+
+static bool __md_early __read_mostly = true;
+static uint8_t __md_earlypages[8 * PAGE_SIZE] __aligned(PAGE_SIZE);
+static size_t __md_earlytaken = 0;
+
+static inline int8_t *
+kasan_md_addr_to_shad(const void *addr)
+{
+ vaddr_t va = (vaddr_t)addr;
+ return (int8_t *)(KASAN_MD_SHADOW_START +
+ ((va - __MD_CANONICAL_BASE) >> KASAN_SHADOW_SCALE_SHIFT));
+}
+
+static inline bool
+kasan_md_unsupported(vaddr_t addr)
+{
+ return (addr >= (vaddr_t)PTE_BASE &&
+ addr < ((vaddr_t)PTE_BASE + NBPD_L4));
+}
+
+static paddr_t
+__md_early_palloc(void)
+{
+ paddr_t ret;
+
+ KASSERT(__md_earlytaken < 8);
+
+ ret = (paddr_t)(&__md_earlypages[0] + __md_earlytaken * PAGE_SIZE);
+ __md_earlytaken++;
+
+ ret -= KERNBASE;
+
+ return ret;
+}
+
+static paddr_t
+__md_palloc(void)
+{
+ paddr_t pa;
+
+ if (__predict_false(__md_early))
+ pa = __md_early_palloc();
+ else
+ pa = pmap_get_physpage();
+
+ return pa;
+}
+
+static void
+kasan_md_shadow_map_page(vaddr_t va)
+{
+ paddr_t pa;
+
+ if (!pmap_valid_entry(L4_BASE[pl4_i(va)])) {
+ pa = __md_palloc();
+ L4_BASE[pl4_i(va)] = pa | PG_KW | pmap_pg_nx | PG_V;
+ }
+ if (!pmap_valid_entry(L3_BASE[pl3_i(va)])) {
+ pa = __md_palloc();
+ L3_BASE[pl3_i(va)] = pa | PG_KW | pmap_pg_nx | PG_V;
+ }
+ if (!pmap_valid_entry(L2_BASE[pl2_i(va)])) {
+ pa = __md_palloc();
+ L2_BASE[pl2_i(va)] = pa | PG_KW | pmap_pg_nx | PG_V;
+ }
+ if (!pmap_valid_entry(L1_BASE[pl1_i(va)])) {
+ pa = __md_palloc();
+ L1_BASE[pl1_i(va)] = pa | PG_KW | pmap_pg_g | pmap_pg_nx | PG_V;
+ }
+}
+
+/*
+ * Map only the current stack. We will map the rest in kasan_init.
+ */
+static void
+kasan_md_early_init(void *stack)
+{
+ kasan_shadow_map(stack, USPACE);
+ __md_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.
+ */
+static void
+kasan_md_init(void)
+{
+ extern struct bootspace bootspace;
+ size_t i;
+
+ CTASSERT((__MD_SHADOW_SIZE / NBPD_L4) == NL4_SLOT_KASAN);
+
+ /* Kernel. */
+ for (i = 0; i < BTSPACE_NSEGS; i++) {
+ if (bootspace.segs[i].type == BTSEG_NONE) {
+ continue;
+ }
+ kasan_shadow_map((void *)bootspace.segs[i].va,
+ bootspace.segs[i].sz);
+ }
+
+ /* Boot region. */
+ kasan_shadow_map((void *)bootspace.boot.va, bootspace.boot.sz);
+
+ /* Module map. */
+ kasan_shadow_map((void *)bootspace.smodule,
+ (size_t)(bootspace.emodule - bootspace.smodule));
+
+ /* The bootstrap spare va. */
+ kasan_shadow_map((void *)bootspace.spareva, PAGE_SIZE);
+}
+
+static inline bool
+__md_unwind_end(const char *name)
+{
+ if (!strcmp(name, "syscall") ||
+ !strcmp(name, "handle_syscall") ||
+ !strncmp(name, "Xintr", 5) ||
+ !strncmp(name, "Xhandle", 7) ||
+ !strncmp(name, "Xresume", 7) ||
+ !strncmp(name, "Xstray", 6) ||
+ !strncmp(name, "Xhold", 5) ||
+ !strncmp(name, "Xrecurse", 8) ||
+ !strcmp(name, "Xdoreti") ||
+ !strncmp(name, "Xsoft", 5)) {
+ return true;
+ }
+
+ return false;
+}
+
+static void
+kasan_md_unwind(void)
+{
+ uint64_t *rbp, rip;
+ const char *mod;
+ const char *sym;
+ size_t nsym;
+ int error;
+
+ rbp = (uint64_t *)__builtin_frame_address(0);
+ nsym = 0;
+
+ while (1) {
+ /* 8(%rbp) contains the saved %rip. */
+ rip = *(rbp + 1);
+
+ if (rip < KERNBASE) {
+ break;
+ }
+ error = ksyms_getname(&mod, &sym, (vaddr_t)rip, KSYMS_PROC);
+ if (error) {
+ break;
+ }
+ printf("#%zu %p in %s <%s>\n", nsym, (void *)rip, sym, mod);
+ if (__md_unwind_end(sym)) {
+ break;
+ }
+
+ rbp = (uint64_t *)*(rbp);
+ if (rbp == 0) {
+ break;
+ }
+ nsym++;
+
+ if (nsym >= 15) {
+ break;
+ }
+ }
+}
Index: src/sys/kern/subr_asan.c
diff -u /dev/null src/sys/kern/subr_asan.c:1.1
--- /dev/null Wed Oct 31 06:26:26 2018
+++ src/sys/kern/subr_asan.c Wed Oct 31 06:26:26 2018
@@ -0,0 +1,536 @@
+/* $NetBSD: subr_asan.c,v 1.1 2018/10/31 06:26:26 maxv Exp $ */
+
+/*
+ * Copyright (c) 2018 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Maxime Villard.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: subr_asan.c,v 1.1 2018/10/31 06:26:26 maxv Exp $");
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/asan.h>
+
+#include <uvm/uvm.h>
+
+/* ASAN constants. Part of the compiler ABI. */
+#define KASAN_SHADOW_SCALE_SHIFT 3
+#define KASAN_SHADOW_SCALE_SIZE (1UL << KASAN_SHADOW_SCALE_SHIFT)
+#define KASAN_SHADOW_MASK (KASAN_SHADOW_SCALE_SIZE - 1)
+
+/* The MD code. */
+#include <machine/asan.h>
+
+/* Our redzone values. */
+#define KASAN_GLOBAL_REDZONE 0xFA
+#define KASAN_MEMORY_REDZONE 0xFB
+
+/* Stack redzone values. Part of the compiler ABI. */
+#define KASAN_STACK_LEFT 0xF1
+#define KASAN_STACK_MID 0xF2
+#define KASAN_STACK_RIGHT 0xF3
+#define KASAN_STACK_PARTIAL 0xF4
+#define KASAN_USE_AFTER_SCOPE 0xF8
+
+/* ASAN ABI version. */
+#if defined(__clang__) && (__clang_major__ - 0 >= 6)
+#define ASAN_ABI_VERSION 8
+#elif __GNUC_PREREQ__(7, 1) && !defined(__clang__)
+#define ASAN_ABI_VERSION 8
+#elif __GNUC_PREREQ__(6, 1) && !defined(__clang__)
+#define ASAN_ABI_VERSION 6
+#else
+#error "Unsupported compiler version"
+#endif
+
+#define __RET_ADDR (unsigned long)__builtin_return_address(0)
+
+/* Global variable descriptor. Part of the compiler ABI. */
+struct __asan_global_source_location {
+ const char *filename;
+ int line_no;
+ int column_no;
+};
+struct __asan_global {
+ const void *beg; /* address of the global variable */
+ size_t size; /* size of the global variable */
+ size_t size_with_redzone; /* size with the redzone */
+ const void *name; /* name of the variable */
+ const void *module_name; /* name of the module where the var is declared */
+ unsigned long has_dynamic_init; /* the var has dyn initializer (c++) */
+ struct __asan_global_source_location *location;
+#if ASAN_ABI_VERSION >= 7
+ uintptr_t odr_indicator; /* the address of the ODR indicator symbol */
+#endif
+};
+
+static bool kasan_enabled __read_mostly = false;
+
+/* -------------------------------------------------------------------------- */
+
+void
+kasan_shadow_map(void *addr, size_t size)
+{
+ size_t sz, npages, i;
+ vaddr_t sva, eva;
+
+ KASSERT((vaddr_t)addr % KASAN_SHADOW_SCALE_SIZE == 0);
+
+ sz = roundup(size, KASAN_SHADOW_SCALE_SIZE) / KASAN_SHADOW_SCALE_SIZE;
+
+ sva = (vaddr_t)kasan_md_addr_to_shad(addr);
+ eva = (vaddr_t)kasan_md_addr_to_shad(addr) + sz;
+
+ sva = rounddown(sva, PAGE_SIZE);
+ eva = roundup(eva, PAGE_SIZE);
+
+ npages = (eva - sva) / PAGE_SIZE;
+
+ KASSERT(sva >= KASAN_MD_SHADOW_START && eva < KASAN_MD_SHADOW_END);
+
+ for (i = 0; i < npages; i++) {
+ kasan_md_shadow_map_page(sva + i * PAGE_SIZE);
+ }
+}
+
+static void
+kasan_ctors(void)
+{
+ extern uint64_t __CTOR_LIST__, __CTOR_END__;
+ size_t nentries, i;
+ uint64_t *ptr;
+
+ nentries = ((size_t)&__CTOR_END__ - (size_t)&__CTOR_LIST__) /
+ sizeof(uintptr_t);
+
+ ptr = &__CTOR_LIST__;
+ for (i = 0; i < nentries; i++) {
+ void (*func)(void);
+
+ func = (void *)(*ptr);
+ (*func)();
+
+ ptr++;
+ }
+}
+
+void
+kasan_early_init(void *stack)
+{
+ kasan_md_early_init(stack);
+}
+
+void
+kasan_init(void)
+{
+ /* MD initialization. */
+ kasan_md_init();
+
+ /* Now officially enabled. */
+ kasan_enabled = true;
+
+ /* Call the ASAN constructors. */
+ kasan_ctors();
+}
+
+static void
+kasan_report(unsigned long addr, size_t size, bool write, unsigned long pc)
+{
+ printf("kASan: Unauthorized Access In %p: Addr %p [%zu byte%s, %s]\n",
+ (void *)pc, (void *)addr, size, (size > 1 ? "s" : ""),
+ (write ? "write" : "read"));
+ kasan_md_unwind();
+}
+
+static __always_inline void
+kasan_shadow_1byte_markvalid(unsigned long addr)
+{
+ int8_t *byte = kasan_md_addr_to_shad((void *)addr);
+ int8_t last = (addr & KASAN_SHADOW_MASK) + 1;
+
+ *byte = last;
+}
+
+static __always_inline void
+kasan_shadow_Nbyte_fill(const void *addr, size_t size, uint8_t val)
+{
+ void *shad;
+
+ if (__predict_false(size == 0))
+ return;
+ if (__predict_false(kasan_md_unsupported((vaddr_t)addr)))
+ return;
+
+ KASSERT((vaddr_t)addr % KASAN_SHADOW_SCALE_SIZE == 0);
+ KASSERT(size % KASAN_SHADOW_SCALE_SIZE == 0);
+
+ shad = (void *)kasan_md_addr_to_shad(addr);
+ size = size >> KASAN_SHADOW_SCALE_SHIFT;
+
+ __builtin_memset(shad, val, size);
+}
+
+void
+kasan_add_redzone(size_t *size)
+{
+ *size = roundup(*size, KASAN_SHADOW_SCALE_SIZE);
+ *size += KASAN_SHADOW_SCALE_SIZE;
+}
+
+static void
+kasan_markmem(const void *addr, size_t size, bool valid)
+{
+ size_t i;
+
+ KASSERT((vaddr_t)addr % KASAN_SHADOW_SCALE_SIZE == 0);
+
+ if (valid) {
+ for (i = 0; i < size; i++) {
+ kasan_shadow_1byte_markvalid((unsigned long)addr+i);
+ }
+ } else {
+ KASSERT(size % KASAN_SHADOW_SCALE_SIZE == 0);
+ kasan_shadow_Nbyte_fill(addr, size, KASAN_MEMORY_REDZONE);
+ }
+}
+
+void
+kasan_softint(struct lwp *l)
+{
+ const void *stk = (const void *)uvm_lwp_getuarea(l);
+
+ kasan_shadow_Nbyte_fill(stk, USPACE, 0);
+}
+
+void
+kasan_alloc(const void *addr, size_t size, size_t sz_with_redz)
+{
+ kasan_markmem(addr, sz_with_redz, false);
+ kasan_markmem(addr, size, true);
+}
+
+void
+kasan_free(const void *addr, size_t sz_with_redz)
+{
+ kasan_markmem(addr, sz_with_redz, true);
+}
+
+/* -------------------------------------------------------------------------- */
+
+#define ADDR_CROSSES_SCALE_BOUNDARY(addr, size) \
+ (addr >> KASAN_SHADOW_SCALE_SHIFT) != \
+ ((addr + size - 1) >> KASAN_SHADOW_SCALE_SHIFT)
+
+static __always_inline bool
+kasan_shadow_1byte_isvalid(unsigned long addr)
+{
+ 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);
+}
+
+static __always_inline bool
+kasan_shadow_2byte_isvalid(unsigned long addr)
+{
+ int8_t *byte, last;
+
+ if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 2)) {
+ return (kasan_shadow_1byte_isvalid(addr) &&
+ kasan_shadow_1byte_isvalid(addr+1));
+ }
+
+ byte = kasan_md_addr_to_shad((void *)addr);
+ last = ((addr + 1) & KASAN_SHADOW_MASK) + 1;
+
+ return __predict_true(*byte == 0 || last <= *byte);
+}
+
+static __always_inline bool
+kasan_shadow_4byte_isvalid(unsigned long addr)
+{
+ int8_t *byte, last;
+
+ if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 4)) {
+ return (kasan_shadow_2byte_isvalid(addr) &&
+ kasan_shadow_2byte_isvalid(addr+2));
+ }
+
+ byte = kasan_md_addr_to_shad((void *)addr);
+ last = ((addr + 3) & KASAN_SHADOW_MASK) + 1;
+
+ return __predict_true(*byte == 0 || last <= *byte);
+}
+
+static __always_inline bool
+kasan_shadow_8byte_isvalid(unsigned long addr)
+{
+ int8_t *byte, last;
+
+ if (ADDR_CROSSES_SCALE_BOUNDARY(addr, 8)) {
+ return (kasan_shadow_4byte_isvalid(addr) &&
+ kasan_shadow_4byte_isvalid(addr+4));
+ }
+
+ byte = kasan_md_addr_to_shad((void *)addr);
+ last = ((addr + 7) & KASAN_SHADOW_MASK) + 1;
+
+ return __predict_true(*byte == 0 || last <= *byte);
+}
+
+static __always_inline bool
+kasan_shadow_Nbyte_isvalid(unsigned long addr, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ if (!kasan_shadow_1byte_isvalid(addr+i))
+ return false;
+ }
+
+ return true;
+}
+
+static __always_inline void
+kasan_shadow_check(unsigned long addr, size_t size, bool write,
+ unsigned long retaddr)
+{
+ bool valid;
+
+ if (__predict_false(!kasan_enabled))
+ return;
+ if (__predict_false(size == 0))
+ return;
+ if (__predict_false(kasan_md_unsupported(addr)))
+ return;
+
+ if (__builtin_constant_p(size)) {
+ switch (size) {
+ case 1:
+ valid = kasan_shadow_1byte_isvalid(addr);
+ break;
+ case 2:
+ valid = kasan_shadow_2byte_isvalid(addr);
+ break;
+ case 4:
+ valid = kasan_shadow_4byte_isvalid(addr);
+ break;
+ case 8:
+ valid = kasan_shadow_8byte_isvalid(addr);
+ break;
+ default:
+ valid = kasan_shadow_Nbyte_isvalid(addr, size);
+ break;
+ }
+ } else {
+ valid = kasan_shadow_Nbyte_isvalid(addr, size);
+ }
+
+ if (__predict_false(!valid)) {
+ kasan_report(addr, size, write, retaddr);
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+void *
+kasan_memcpy(void *dst, const void *src, size_t len)
+{
+ kasan_shadow_check((unsigned long)src, len, false, __RET_ADDR);
+ kasan_shadow_check((unsigned long)dst, len, true, __RET_ADDR);
+ return __builtin_memcpy(dst, src, len);
+}
+
+int
+kasan_memcmp(const void *b1, const void *b2, size_t len)
+{
+ kasan_shadow_check((unsigned long)b1, len, false, __RET_ADDR);
+ kasan_shadow_check((unsigned long)b2, len, false, __RET_ADDR);
+ return __builtin_memcmp(b1, b2, len);
+}
+
+void *
+kasan_memset(void *b, int c, size_t len)
+{
+ kasan_shadow_check((unsigned long)b, len, true, __RET_ADDR);
+ return __builtin_memset(b, c, len);
+}
+
+char *
+kasan_strcpy(char *dst, const char *src)
+{
+ char *save = dst;
+
+ while (1) {
+ kasan_shadow_check((unsigned long)src, 1, false, __RET_ADDR);
+ kasan_shadow_check((unsigned long)dst, 1, true, __RET_ADDR);
+ *dst = *src;
+ if (*src == '\0')
+ break;
+ src++, dst++;
+ }
+
+ return save;
+}
+
+int
+kasan_strcmp(const char *s1, const char *s2)
+{
+ while (1) {
+ kasan_shadow_check((unsigned long)s1, 1, false, __RET_ADDR);
+ kasan_shadow_check((unsigned long)s2, 1, false, __RET_ADDR);
+ if (*s1 != *s2)
+ break;
+ if (*s1 == '\0')
+ return 0;
+ s1++, s2++;
+ }
+
+ return (*(const unsigned char *)s1 - *(const unsigned char *)s2);
+}
+
+size_t
+kasan_strlen(const char *str)
+{
+ const char *s;
+
+ s = str;
+ while (1) {
+ kasan_shadow_check((unsigned long)s, 1, false, __RET_ADDR);
+ if (*s == '\0')
+ break;
+ s++;
+ }
+
+ return (s - str);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void __asan_register_globals(struct __asan_global *, size_t);
+void __asan_unregister_globals(struct __asan_global *, size_t);
+
+void
+__asan_register_globals(struct __asan_global *globals, size_t n)
+{
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ kasan_alloc(globals[i].beg, globals[i].size,
+ globals[i].size_with_redzone);
+ }
+}
+
+void
+__asan_unregister_globals(struct __asan_global *globals, size_t n)
+{
+ /* never called */
+}
+
+#define ASAN_LOAD_STORE(size) \
+ void __asan_load##size(unsigned long); \
+ void __asan_load##size(unsigned long addr) \
+ { \
+ kasan_shadow_check(addr, size, false, __RET_ADDR);\
+ } \
+ void __asan_load##size##_noabort(unsigned long); \
+ void __asan_load##size##_noabort(unsigned long addr) \
+ { \
+ kasan_shadow_check(addr, size, false, __RET_ADDR);\
+ } \
+ void __asan_store##size(unsigned long); \
+ void __asan_store##size(unsigned long addr) \
+ { \
+ kasan_shadow_check(addr, size, true, __RET_ADDR);\
+ } \
+ void __asan_store##size##_noabort(unsigned long); \
+ void __asan_store##size##_noabort(unsigned long addr) \
+ { \
+ kasan_shadow_check(addr, size, true, __RET_ADDR);\
+ }
+
+ASAN_LOAD_STORE(1);
+ASAN_LOAD_STORE(2);
+ASAN_LOAD_STORE(4);
+ASAN_LOAD_STORE(8);
+ASAN_LOAD_STORE(16);
+
+void __asan_loadN(unsigned long, size_t);
+void __asan_loadN_noabort(unsigned long, size_t);
+void __asan_storeN(unsigned long, size_t);
+void __asan_storeN_noabort(unsigned long, size_t);
+void __asan_handle_no_return(void);
+
+void
+__asan_loadN(unsigned long addr, size_t size)
+{
+ kasan_shadow_check(addr, size, false, __RET_ADDR);
+}
+
+void
+__asan_loadN_noabort(unsigned long addr, size_t size)
+{
+ kasan_shadow_check(addr, size, false, __RET_ADDR);
+}
+
+void
+__asan_storeN(unsigned long addr, size_t size)
+{
+ kasan_shadow_check(addr, size, true, __RET_ADDR);
+}
+
+void
+__asan_storeN_noabort(unsigned long addr, size_t size)
+{
+ kasan_shadow_check(addr, size, true, __RET_ADDR);
+}
+
+void
+__asan_handle_no_return(void)
+{
+ /* nothing */
+}
+
+#define ASAN_SET_SHADOW(byte) \
+ void __asan_set_shadow_##byte(void *, size_t); \
+ void __asan_set_shadow_##byte(void *addr, size_t size) \
+ { \
+ __builtin_memset((void *)addr, 0x##byte, size); \
+ }
+
+ASAN_SET_SHADOW(00);
+ASAN_SET_SHADOW(f1);
+ASAN_SET_SHADOW(f2);
+ASAN_SET_SHADOW(f3);
+ASAN_SET_SHADOW(f5);
+ASAN_SET_SHADOW(f8);