aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Evans <kevans@FreeBSD.org>2023-03-23 21:26:06 +0000
committerKyle Evans <kevans@FreeBSD.org>2023-03-23 21:34:33 +0000
commit89c52f9d59fa796cc6cce44d34c93ec802abb15a (patch)
tree105f720ac7bfad2cf415c7a6bc5b9548e7524017
parent698dbd66fed21e0acabf02a07be5080d016efa5c (diff)
downloadsrc-89c52f9d59fa.tar.gz
src-89c52f9d59fa.zip
arm64: add KASAN support
This entails: - Marking some obvious candidates for __nosanitizeaddress - Similar trap frame markings as amd64, for similar reasons - Shadow map implementation The shadow map implementation is roughly similar to what was done on amd64, with some exceptions. Attempting to use available space at preinit_map_va + PMAP_PREINIT_MAPPING_SIZE (up to the end of that range, as depicted in the physmap) results in odd failures, so we instead search the physmap for free regions that we can carve out, fragmenting the shadow map as necessary to try and fit as much as we need for the initial kernel map. pmap_bootstrap_san() is thus after pmap_bootstrap(), which still included some technically reserved areas of the memory map that needed to be included in the DMAP. The odd failure noted above may be a bug, but I haven't investigated it all that much. Initial work by mhorne with additional fixes from kevans and markj. Reviewed by: andrew, markj Sponsored by: Juniper Networks, Inc. Sponsored by: Klara, Inc. Differential Revision: https://reviews.freebsd.org/D36701
-rw-r--r--sys/arm64/arm64/db_trace.c6
-rw-r--r--sys/arm64/arm64/locore.S11
-rw-r--r--sys/arm64/arm64/machdep.c14
-rw-r--r--sys/arm64/arm64/pmap.c266
-rw-r--r--sys/arm64/arm64/trap.c5
-rw-r--r--sys/arm64/include/asan.h68
-rw-r--r--sys/arm64/include/atomic.h5
-rw-r--r--sys/arm64/include/param.h4
-rw-r--r--sys/arm64/include/pmap.h8
-rw-r--r--sys/arm64/include/vmparam.h11
-rw-r--r--sys/conf/files.arm643
-rw-r--r--sys/conf/kern.pre.mk11
-rw-r--r--sys/kern/subr_intr.c3
13 files changed, 409 insertions, 6 deletions
diff --git a/sys/arm64/arm64/db_trace.c b/sys/arm64/arm64/db_trace.c
index 42230f273716..612cea5f41cf 100644
--- a/sys/arm64/arm64/db_trace.c
+++ b/sys/arm64/arm64/db_trace.c
@@ -56,7 +56,7 @@ db_md_list_watchpoints(void)
dbg_show_watchpoint();
}
-static void
+static void __nosanitizeaddress
db_stack_trace_cmd(struct thread *td, struct unwind_state *frame)
{
c_db_sym_t sym;
@@ -135,7 +135,7 @@ db_stack_trace_cmd(struct thread *td, struct unwind_state *frame)
}
}
-int
+int __nosanitizeaddress
db_trace_thread(struct thread *thr, int count)
{
struct unwind_state frame;
@@ -152,7 +152,7 @@ db_trace_thread(struct thread *thr, int count)
return (0);
}
-void
+void __nosanitizeaddress
db_trace_self(void)
{
struct unwind_state frame;
diff --git a/sys/arm64/arm64/locore.S b/sys/arm64/arm64/locore.S
index 1080ebc6217e..a73941a01492 100644
--- a/sys/arm64/arm64/locore.S
+++ b/sys/arm64/arm64/locore.S
@@ -148,6 +148,17 @@ virtdone:
str x23, [x0, #BP_BOOT_EL]
str x4, [x0, #BP_HCR_EL2]
+#ifdef KASAN
+ /* Save bootparams */
+ mov x19, x0
+
+ /* Bootstrap an early shadow map for the boot stack. */
+ bl pmap_san_bootstrap
+
+ /* Restore bootparams */
+ mov x0, x19
+#endif
+
/* trace back starts here */
mov fp, #0
/* Branch to C code */
diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c
index 31e7568a0605..b87c635048de 100644
--- a/sys/arm64/arm64/machdep.c
+++ b/sys/arm64/arm64/machdep.c
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/asan.h>
#include <sys/buf.h>
#include <sys/bus.h>
#include <sys/cons.h>
@@ -955,6 +956,18 @@ initarm(struct arm64_bootparams *abp)
/* Do the same for reserve entries in the EFI MEMRESERVE table */
if (efi_systbl_phys != 0)
exclude_efi_memreserve(efi_systbl_phys);
+
+ /*
+ * We carefully bootstrap the sanitizer map after we've excluded
+ * absolutely everything else that could impact phys_avail. There's not
+ * always enough room for the initial shadow map after the kernel, so
+ * we'll end up searching for segments that we can safely use. Those
+ * segments also get excluded from phys_avail.
+ */
+#if defined(KASAN)
+ pmap_bootstrap_san(KERNBASE - abp->kern_delta);
+#endif
+
physmem_init_kernel_globals();
devmap_bootstrap(0, NULL);
@@ -998,6 +1011,7 @@ initarm(struct arm64_bootparams *abp)
pan_enable();
kcsan_cpu_init(0);
+ kasan_init();
env = kern_getenv("kernelname");
if (env != NULL)
diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index 17abce473c17..b62673f999e6 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -108,6 +108,7 @@ __FBSDID("$FreeBSD$");
#include "opt_vm.h"
#include <sys/param.h>
+#include <sys/asan.h>
#include <sys/bitstring.h>
#include <sys/bus.h>
#include <sys/systm.h>
@@ -146,6 +147,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_dumpset.h>
#include <vm/uma.h>
+#include <machine/asan.h>
#include <machine/machdep.h>
#include <machine/md_var.h>
#include <machine/pcb.h>
@@ -190,6 +192,9 @@ __FBSDID("$FreeBSD$");
#define pmap_l1_pindex(v) (NUL2E + ((v) >> L1_SHIFT))
#define pmap_l2_pindex(v) ((v) >> L2_SHIFT)
+#define PMAP_SAN_PTE_BITS (ATTR_DEFAULT | ATTR_S1_XN | \
+ ATTR_S1_IDX(VM_MEMATTR_WRITE_BACK) | ATTR_S1_AP(ATTR_S1_AP_RW))
+
struct pmap_large_md_page {
struct rwlock pv_lock;
struct md_page pv_page;
@@ -1211,6 +1216,54 @@ pmap_bootstrap_l3(vm_offset_t va)
pmap_bootstrap_l2_table(&bs_state);
}
+#ifdef KASAN
+static void
+pmap_bootstrap_allocate_kasan_l2(vm_paddr_t start_pa, vm_paddr_t end_pa,
+ vm_offset_t *start_va, int *nkasan_l2)
+{
+ int i;
+ vm_paddr_t pa;
+ vm_offset_t va;
+ pd_entry_t *l2;
+
+ va = *start_va;
+ pa = rounddown2(end_pa - L2_SIZE, L2_SIZE);
+ l2 = pmap_l2(kernel_pmap, va);
+
+ for (i = 0; pa >= start_pa && i < *nkasan_l2;
+ i++, va += L2_SIZE, pa -= L2_SIZE, l2++) {
+ /*
+ * KASAN stack checking results in us having already allocated
+ * part of our shadow map, so we can just skip those segments.
+ */
+ if ((pmap_load(l2) & ATTR_DESCR_VALID) != 0) {
+ pa += L2_SIZE;
+ continue;
+ }
+
+ pmap_store(l2, (pa & ~Ln_TABLE_MASK) | PMAP_SAN_PTE_BITS |
+ L2_BLOCK);
+ }
+
+ /*
+ * Ended the allocation due to start_pa constraint, rather than because
+ * we allocated everything. Adjust back up to the start_pa and remove
+ * the invalid L2 block from our accounting.
+ */
+ if (pa < start_pa) {
+ va += L2_SIZE;
+ i--;
+ pa = start_pa;
+ }
+
+ bzero((void *)PHYS_TO_DMAP(pa), i * L2_SIZE);
+ physmem_exclude_region(pa, i * L2_SIZE, EXFLAG_NOALLOC);
+
+ *nkasan_l2 -= i;
+ *start_va = va;
+}
+#endif
+
/*
* Bootstrap the system enough to run with virtual memory.
*/
@@ -1312,6 +1365,68 @@ pmap_bootstrap(vm_paddr_t kernstart, vm_size_t kernlen)
cpu_tlb_flushID();
}
+#if defined(KASAN)
+/*
+ * Finish constructing the initial shadow map:
+ * - Count how many pages from KERNBASE to virtual_avail (scaled for
+ * shadow map)
+ * - Map that entire range using L2 superpages.
+ */
+void
+pmap_bootstrap_san(vm_paddr_t kernstart)
+{
+ vm_offset_t va;
+ int i, shadow_npages, nkasan_l2;
+
+ /*
+ * Rebuild physmap one more time, we may have excluded more regions from
+ * allocation since pmap_bootstrap().
+ */
+ bzero(physmap, sizeof(physmap));
+ physmap_idx = physmem_avail(physmap, nitems(physmap));
+ physmap_idx /= 2;
+
+ shadow_npages = (virtual_avail - VM_MIN_KERNEL_ADDRESS) / PAGE_SIZE;
+ shadow_npages = howmany(shadow_npages, KASAN_SHADOW_SCALE);
+ nkasan_l2 = howmany(shadow_npages, Ln_ENTRIES);
+
+ /* Map the valid KVA up to this point. */
+ va = KASAN_MIN_ADDRESS;
+
+ /*
+ * Find a slot in the physmap large enough for what we needed. We try to put
+ * the shadow map as high up as we can to avoid depleting the lower 4GB in case
+ * it's needed for, e.g., an xhci controller that can only do 32-bit DMA.
+ */
+ for (i = (physmap_idx * 2) - 2; i >= 0 && nkasan_l2 > 0; i -= 2) {
+ vm_paddr_t plow, phigh;
+
+ /* L2 mappings must be backed by memory that is L2-aligned */
+ plow = roundup2(physmap[i], L2_SIZE);
+ phigh = physmap[i + 1];
+ if (plow >= phigh)
+ continue;
+ if (kernstart >= plow && kernstart < phigh)
+ phigh = kernstart;
+ if (phigh - plow >= L2_SIZE)
+ pmap_bootstrap_allocate_kasan_l2(plow, phigh, &va,
+ &nkasan_l2);
+ }
+
+ if (nkasan_l2 != 0)
+ panic("Could not find phys region for shadow map");
+
+ /*
+ * Done. We should now have a valid shadow address mapped for all KVA
+ * that has been mapped so far, i.e., KERNBASE to virtual_avail. Thus,
+ * shadow accesses by the kasan(9) runtime will succeed for this range.
+ * When the kernel virtual address range is later expanded, as will
+ * happen in vm_mem_init(), the shadow map will be grown as well. This
+ * is handled by pmap_san_enter().
+ */
+}
+#endif
+
/*
* Initialize a vm_page's machine-dependent fields.
*/
@@ -2580,6 +2695,8 @@ pmap_growkernel(vm_offset_t addr)
addr = roundup2(addr, L2_SIZE);
if (addr - 1 >= vm_map_max(kernel_map))
addr = vm_map_max(kernel_map);
+ if (kernel_vm_end < addr)
+ kasan_shadow_map(kernel_vm_end, addr - kernel_vm_end);
while (kernel_vm_end < addr) {
l0 = pmap_l0(kernel_pmap, kernel_vm_end);
KASSERT(pmap_load(l0) != 0,
@@ -7556,6 +7673,151 @@ pmap_is_valid_memattr(pmap_t pmap __unused, vm_memattr_t mode)
return (mode >= VM_MEMATTR_DEVICE && mode <= VM_MEMATTR_WRITE_THROUGH);
}
+#if defined(KASAN)
+static vm_paddr_t pmap_san_early_kernstart;
+static pd_entry_t *pmap_san_early_l2;
+
+void __nosanitizeaddress
+pmap_san_bootstrap(struct arm64_bootparams *abp)
+{
+
+ pmap_san_early_kernstart = KERNBASE - abp->kern_delta;
+ kasan_init_early(abp->kern_stack, KSTACK_PAGES * PAGE_SIZE);
+}
+
+#define SAN_BOOTSTRAP_L2_SIZE (1 * L2_SIZE)
+#define SAN_BOOTSTRAP_SIZE (2 * PAGE_SIZE)
+static vm_offset_t __nosanitizeaddress
+pmap_san_enter_bootstrap_alloc_l2(void)
+{
+ static uint8_t bootstrap_data[SAN_BOOTSTRAP_L2_SIZE] __aligned(L2_SIZE);
+ static size_t offset = 0;
+ vm_offset_t addr;
+
+ if (offset + L2_SIZE > sizeof(bootstrap_data)) {
+ panic("%s: out of memory for the bootstrap shadow map L2 entries",
+ __func__);
+ }
+
+ addr = (uintptr_t)&bootstrap_data[offset];
+ offset += L2_SIZE;
+ return (addr);
+}
+
+/*
+ * SAN L1 + L2 pages, maybe L3 entries later?
+ */
+static vm_offset_t __nosanitizeaddress
+pmap_san_enter_bootstrap_alloc_pages(int npages)
+{
+ static uint8_t bootstrap_data[SAN_BOOTSTRAP_SIZE] __aligned(PAGE_SIZE);
+ static size_t offset = 0;
+ vm_offset_t addr;
+
+ if (offset + (npages * PAGE_SIZE) > sizeof(bootstrap_data)) {
+ panic("%s: out of memory for the bootstrap shadow map",
+ __func__);
+ }
+
+ addr = (uintptr_t)&bootstrap_data[offset];
+ offset += (npages * PAGE_SIZE);
+ return (addr);
+}
+
+static void __nosanitizeaddress
+pmap_san_enter_bootstrap(void)
+{
+ vm_offset_t freemempos;
+
+ /* L1, L2 */
+ freemempos = pmap_san_enter_bootstrap_alloc_pages(2);
+ bs_state.freemempos = freemempos;
+ bs_state.va = KASAN_MIN_ADDRESS;
+ pmap_bootstrap_l1_table(&bs_state);
+ pmap_san_early_l2 = bs_state.l2;
+}
+
+static vm_page_t
+pmap_san_enter_alloc_l3(void)
+{
+ vm_page_t m;
+
+ m = vm_page_alloc_noobj(VM_ALLOC_INTERRUPT | VM_ALLOC_WIRED |
+ VM_ALLOC_ZERO);
+ if (m == NULL)
+ panic("%s: no memory to grow shadow map", __func__);
+ return (m);
+}
+
+static vm_page_t
+pmap_san_enter_alloc_l2(void)
+{
+ return (vm_page_alloc_noobj_contig(VM_ALLOC_WIRED | VM_ALLOC_ZERO,
+ Ln_ENTRIES, 0, ~0ul, L2_SIZE, 0, VM_MEMATTR_DEFAULT));
+}
+
+void __nosanitizeaddress
+pmap_san_enter(vm_offset_t va)
+{
+ pd_entry_t *l1, *l2;
+ pt_entry_t *l3;
+ vm_page_t m;
+
+ if (virtual_avail == 0) {
+ vm_offset_t block;
+ int slot;
+ bool first;
+
+ /* Temporary shadow map prior to pmap_bootstrap(). */
+ first = pmap_san_early_l2 == NULL;
+ if (first)
+ pmap_san_enter_bootstrap();
+
+ l2 = pmap_san_early_l2;
+ slot = pmap_l2_index(va);
+
+ if ((pmap_load(&l2[slot]) & ATTR_DESCR_VALID) == 0) {
+ MPASS(first);
+ block = pmap_san_enter_bootstrap_alloc_l2();
+ pmap_store(&l2[slot], pmap_early_vtophys(block) |
+ PMAP_SAN_PTE_BITS | L2_BLOCK);
+ dmb(ishst);
+ }
+
+ return;
+ }
+
+ mtx_assert(&kernel_map->system_mtx, MA_OWNED);
+ l1 = pmap_l1(kernel_pmap, va);
+ MPASS(l1 != NULL);
+ if ((pmap_load(l1) & ATTR_DESCR_VALID) == 0) {
+ m = pmap_san_enter_alloc_l3();
+ pmap_store(l1, (VM_PAGE_TO_PHYS(m) & ~Ln_TABLE_MASK) |
+ L1_TABLE);
+ }
+ l2 = pmap_l1_to_l2(l1, va);
+ if ((pmap_load(l2) & ATTR_DESCR_VALID) == 0) {
+ m = pmap_san_enter_alloc_l2();
+ if (m != NULL) {
+ pmap_store(l2, VM_PAGE_TO_PHYS(m) | PMAP_SAN_PTE_BITS |
+ L2_BLOCK);
+ } else {
+ m = pmap_san_enter_alloc_l3();
+ pmap_store(l2, VM_PAGE_TO_PHYS(m) | L2_TABLE);
+ }
+ dmb(ishst);
+ }
+ if ((pmap_load(l2) & ATTR_DESCR_MASK) == L2_BLOCK)
+ return;
+ l3 = pmap_l2_to_l3(l2, va);
+ if ((pmap_load(l3) & ATTR_DESCR_VALID) != 0)
+ return;
+ m = pmap_san_enter_alloc_l3();
+ pmap_store(l3, VM_PAGE_TO_PHYS(m) | PMAP_SAN_PTE_BITS | L3_PAGE);
+ dmb(ishst);
+}
+#endif /* KASAN */
+
/*
* Track a range of the kernel's virtual address space that is contiguous
* in various mapping attributes.
@@ -7724,6 +7986,10 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
sbuf_printf(sb, "\nDirect map:\n");
else if (i == pmap_l0_index(VM_MIN_KERNEL_ADDRESS))
sbuf_printf(sb, "\nKernel map:\n");
+#ifdef KASAN
+ else if (i == pmap_l0_index(KASAN_MIN_ADDRESS))
+ sbuf_printf(sb, "\nKASAN shadow map:\n");
+#endif
l0e = kernel_pmap->pm_l0[i];
if ((l0e & ATTR_DESCR_VALID) == 0) {
diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c
index 1b7d945ff115..367a31cbe1de 100644
--- a/sys/arm64/arm64/trap.c
+++ b/sys/arm64/arm64/trap.c
@@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/asan.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/lock.h>
@@ -465,6 +466,7 @@ do_el1h_sync(struct thread *td, struct trapframe *frame)
uint64_t esr, far;
int dfsc;
+ kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0);
far = frame->tf_far;
/* Read the esr register to get the exception details */
esr = frame->tf_esr;
@@ -571,6 +573,7 @@ do_el0_sync(struct thread *td, struct trapframe *frame)
("Invalid pcpu address from userland: %p (tpidr %lx)",
get_pcpu(), READ_SPECIALREG(tpidr_el1)));
+ kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0);
far = frame->tf_far;
esr = frame->tf_esr;
exception = ESR_ELx_EXCEPTION(esr);
@@ -712,6 +715,7 @@ do_serror(struct trapframe *frame)
{
uint64_t esr, far;
+ kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0);
far = frame->tf_far;
esr = frame->tf_esr;
@@ -726,6 +730,7 @@ unhandled_exception(struct trapframe *frame)
{
uint64_t esr, far;
+ kasan_mark(frame, sizeof(*frame), sizeof(*frame), 0);
far = frame->tf_far;
esr = frame->tf_esr;
diff --git a/sys/arm64/include/asan.h b/sys/arm64/include/asan.h
new file mode 100644
index 000000000000..3bea6847a297
--- /dev/null
+++ b/sys/arm64/include/asan.h
@@ -0,0 +1,68 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Mark Johnston under sponsorship from the
+ * FreeBSD Foundation.
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ */
+
+#ifndef _MACHINE_ASAN_H_
+#define _MACHINE_ASAN_H_
+
+#ifdef KASAN
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_page.h>
+#include <machine/vmparam.h>
+
+static inline vm_offset_t
+kasan_md_addr_to_shad(vm_offset_t addr)
+{
+ return (((addr - VM_MIN_KERNEL_ADDRESS) >> KASAN_SHADOW_SCALE_SHIFT) +
+ KASAN_MIN_ADDRESS);
+}
+
+static inline bool
+kasan_md_unsupported(vm_offset_t addr)
+{
+ return (addr < VM_MIN_KERNEL_ADDRESS || addr >= virtual_end);
+}
+
+static inline void
+kasan_md_init(void)
+{
+
+}
+
+static inline void
+kasan_md_init_early(vm_offset_t bootstack, size_t size)
+{
+
+ kasan_shadow_map(bootstack, size);
+}
+
+#endif /* KASAN */
+#endif /* !_MACHINE_ASAN_H_ */
diff --git a/sys/arm64/include/atomic.h b/sys/arm64/include/atomic.h
index 0c750f00379c..b14cd303da3a 100644
--- a/sys/arm64/include/atomic.h
+++ b/sys/arm64/include/atomic.h
@@ -53,6 +53,10 @@
#define wmb() dmb(st) /* Full system memory barrier store */
#define rmb() dmb(ld) /* Full system memory barrier load */
+#ifdef _KERNEL
+extern _Bool lse_supported;
+#endif
+
#if defined(SAN_NEEDS_INTERCEPTORS) && !defined(SAN_RUNTIME)
#include <sys/atomic_san.h>
#else
@@ -60,7 +64,6 @@
#include <sys/atomic_common.h>
#ifdef _KERNEL
-extern bool lse_supported;
#ifdef LSE_ATOMICS
#define _ATOMIC_LSE_SUPPORTED 1
diff --git a/sys/arm64/include/param.h b/sys/arm64/include/param.h
index d34667788938..c94b797f8cca 100644
--- a/sys/arm64/include/param.h
+++ b/sys/arm64/include/param.h
@@ -99,8 +99,12 @@
#define MAXPAGESIZES 3 /* maximum number of supported page sizes */
#ifndef KSTACK_PAGES
+#if defined(KASAN) || defined(KMSAN)
+#define KSTACK_PAGES 6
+#else
#define KSTACK_PAGES 4 /* pages of kernel stack (with pcb) */
#endif
+#endif
#define KSTACK_GUARD_PAGES 1 /* pages of kstack guard; 0 disables */
#define PCPU_PAGES 1
diff --git a/sys/arm64/include/pmap.h b/sys/arm64/include/pmap.h
index eb72f46668c3..2847fa8dd439 100644
--- a/sys/arm64/include/pmap.h
+++ b/sys/arm64/include/pmap.h
@@ -183,6 +183,14 @@ pmap_vmspace_copy(pmap_t dst_pmap __unused, pmap_t src_pmap __unused)
return (0);
}
+#if defined(KASAN) || defined(KMSAN)
+struct arm64_bootparams;
+
+void pmap_bootstrap_san(vm_paddr_t);
+void pmap_san_enter(vm_offset_t);
+void pmap_san_bootstrap(struct arm64_bootparams *);
+#endif
+
#endif /* _KERNEL */
#endif /* !LOCORE */
diff --git a/sys/arm64/include/vmparam.h b/sys/arm64/include/vmparam.h
index e3f48e61b78c..b28a79256453 100644
--- a/sys/arm64/include/vmparam.h
+++ b/sys/arm64/include/vmparam.h
@@ -125,7 +125,10 @@
* Upper region: 0xffffffffffffffff Top of virtual memory
*
* 0xfffffeffffffffff End of DMAP
- * 0xfffffa0000000000 Start of DMAP
+ * 0xffffa00000000000 Start of DMAP
+ *
+ * 0xffff009fffffffff End of KASAN shadow map
+ * 0xffff008000000000 Start of KASAN shadow map
*
* 0xffff007fffffffff End of KVA
* 0xffff000000000000 Kernel base address & start of KVA
@@ -156,6 +159,10 @@
#define VM_MIN_KERNEL_ADDRESS (0xffff000000000000UL)
#define VM_MAX_KERNEL_ADDRESS (0xffff008000000000UL)
+/* 128 GiB KASAN shadow map */
+#define KASAN_MIN_ADDRESS (0xffff008000000000UL)
+#define KASAN_MAX_ADDRESS (0xffff00a000000000UL)
+
/* The address bits that hold a pointer authentication code */
#define PAC_ADDR_MASK (0xff7f000000000000UL)
@@ -239,7 +246,9 @@
#define VM_INITIAL_PAGEIN 16
#endif
+#if !defined(KASAN) && !defined(KMSAN)
#define UMA_MD_SMALL_ALLOC
+#endif
#ifndef LOCORE
diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
index 22dd267b2b42..da63564eba7e 100644
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -80,7 +80,8 @@ arm64/arm64/trap.c standard
arm64/arm64/uio_machdep.c standard
arm64/arm64/uma_machdep.c standard
arm64/arm64/undefined.c standard
-arm64/arm64/unwind.c optional ddb | kdtrace_hooks | stack
+arm64/arm64/unwind.c optional ddb | kdtrace_hooks | stack \
+ compile-with "${NORMAL_C:N-fsanitize*}"
arm64/arm64/vfp.c standard
arm64/arm64/vm_machdep.c standard
diff --git a/sys/conf/kern.pre.mk b/sys/conf/kern.pre.mk
index ec5c1d331533..e401a652bf97 100644
--- a/sys/conf/kern.pre.mk
+++ b/sys/conf/kern.pre.mk
@@ -102,6 +102,17 @@ SAN_CFLAGS+= -DSAN_NEEDS_INTERCEPTORS -DSAN_INTERCEPTOR_PREFIX=kasan \
-mllvm -asan-use-after-scope=true \
-mllvm -asan-instrumentation-with-call-threshold=0 \
-mllvm -asan-instrument-byval=false
+
+.if ${MACHINE_CPUARCH} == "aarch64"
+# KASAN/ARM64 TODO: -asan-mapping-offset is calculated from:
+# (VM_KERNEL_MIN_ADDRESS >> KASAN_SHADOW_SCALE_SHIFT) + $offset = KASAN_MIN_ADDRESS
+#
+# This is different than amd64, where we have a different
+# KASAN_MIN_ADDRESS, and this offset value should eventually be
+# upstreamed similar to: https://reviews.llvm.org/D98285
+#
+SAN_CFLAGS+= -mllvm -asan-mapping-offset=0xdfff208000000000
+.endif
.endif
KCSAN_ENABLED!= grep KCSAN opt_global.h || true ; echo
diff --git a/sys/kern/subr_intr.c b/sys/kern/subr_intr.c
index a95d2adbed04..cbacdf677ee6 100644
--- a/sys/kern/subr_intr.c
+++ b/sys/kern/subr_intr.c
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/asan.h>
#include <sys/bitstring.h>
#include <sys/bus.h>
#include <sys/conf.h>
@@ -345,6 +346,8 @@ intr_irq_handler(struct trapframe *tf)
KASSERT(irq_root_filter != NULL, ("%s: no filter", __func__));
+ kasan_mark(tf, sizeof(*tf), sizeof(*tf), 0);
+
VM_CNT_INC(v_intr);
critical_enter();
td = curthread;