Skip to content

Commit

Permalink
Add support for kASan on amd64. Written by me, with some parts inspired
Browse files Browse the repository at this point in the history
from Siddharth Muralee's initial work. This feature can detect several
kinds of memory bugs, and it's an excellent feature.

It can be enabled by uncommenting these three lines in GENERIC:

	#makeoptions 	KASAN=1		# Kernel Address Sanitizer
	#options 	KASAN
	#no options	SVS

The kernel is compiled without SVS, without DMAP and without PCPU area.
A shadow area is created at boot time, and it can cover the upper 128TB
of the address space. This area is populated gradually as we allocate
memory. With this design the memory consumption is kept at its lowest
level.

The compiler calls the __asan_* functions each time a memory access is
done. We verify whether this access is legal by looking at the shadow
area.

We declare our own special memcpy/memset/etc functions, because the
compiler's builtins don't add the __asan_* instrumentation.

Initially all the mappings are marked as valid. During dynamic
allocations, we add a redzone, which we mark as invalid. Any access on
it will trigger a kASan error message. Additionally, the compiler adds
a redzone on global variables, and we mark these redzones as invalid too.
The illegal-access detection works with a 1-byte granularity.

For now, we cover three areas:

	- global variables
	- kmem_alloc-ated areas
	- malloc-ated areas

More will come, but that's a good start.
  • Loading branch information
maxv authored and maxv committed Aug 20, 2018
1 parent e7996d3 commit ea95040
Show file tree
Hide file tree
Showing 16 changed files with 764 additions and 28 deletions.
591 changes: 591 additions & 0 deletions sys/arch/amd64/amd64/asan.c

Large diffs are not rendered by default.

19 changes: 17 additions & 2 deletions sys/arch/amd64/amd64/machdep.c
@@ -1,4 +1,4 @@
/* $NetBSD: machdep.c,v 1.314 2018/08/12 15:31:01 maxv Exp $ */
/* $NetBSD: machdep.c,v 1.315 2018/08/20 15:04:51 maxv Exp $ */

/*
* Copyright (c) 1996, 1997, 1998, 2000, 2006, 2007, 2008, 2011
Expand Down Expand Up @@ -110,7 +110,7 @@
*/

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.314 2018/08/12 15:31:01 maxv Exp $");
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.315 2018/08/20 15:04:51 maxv Exp $");

#include "opt_modular.h"
#include "opt_user_ldt.h"
Expand All @@ -122,6 +122,7 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.314 2018/08/12 15:31:01 maxv Exp $");
#include "opt_xen.h"
#include "opt_svs.h"
#include "opt_kaslr.h"
#include "opt_kasan.h"
#ifndef XEN
#include "opt_physmem.h"
#endif
Expand Down Expand Up @@ -1656,6 +1657,15 @@ init_slotspace(void)
slotspace.area[SLAREA_HYPV].dropmax = false;
#endif

#ifdef KASAN
/* ASAN. */
slotspace.area[SLAREA_ASAN].sslot = L4_SLOT_KASAN;
slotspace.area[SLAREA_ASAN].mslot = NL4_SLOT_KASAN;
slotspace.area[SLAREA_ASAN].nslot = NL4_SLOT_KASAN;
slotspace.area[SLAREA_ASAN].active = true;
slotspace.area[SLAREA_ASAN].dropmax = false;
#endif

/* Kernel. */
slotspace.area[SLAREA_KERN].sslot = L4_SLOT_KERNBASE;
slotspace.area[SLAREA_KERN].mslot = 1;
Expand Down Expand Up @@ -1781,6 +1791,11 @@ init_x86_64(paddr_t first_avail)

init_x86_msgbuf();

#ifdef KASAN
void kasan_init(void);
kasan_init();
#endif

pmap_growkernel(VM_MIN_KERNEL_ADDRESS + 32 * 1024 * 1024);

kpreempt_disable();
Expand Down
9 changes: 7 additions & 2 deletions sys/arch/amd64/conf/GENERIC
@@ -1,4 +1,4 @@
# $NetBSD: GENERIC,v 1.503 2018/08/14 06:37:59 maxv Exp $
# $NetBSD: GENERIC,v 1.504 2018/08/20 15:04:51 maxv Exp $
#
# GENERIC machine description file
#
Expand All @@ -22,7 +22,7 @@ include "arch/amd64/conf/std.amd64"

options INCLUDE_CONFIG_FILE # embed config file in kernel binary

#ident "GENERIC-$Revision: 1.503 $"
#ident "GENERIC-$Revision: 1.504 $"

maxusers 64 # estimated number of users

Expand Down Expand Up @@ -117,6 +117,11 @@ makeoptions DEBUG="-g" # compile full symbol table for CTF
#options SYSCALL_TIMES_HASCOUNTER # use 'broken' rdtsc (soekris)
options KDTRACE_HOOKS # kernel DTrace hooks

# Kernel Address Sanitizer (kASan). You need to disable SVS to use it.
#makeoptions KASAN=1 # Kernel Address Sanitizer
#options KASAN
#no options SVS

# Compatibility options
# x86_64 never shipped with a.out binaries; the two options below are
# only relevant to 32-bit i386 binaries
Expand Down
7 changes: 6 additions & 1 deletion sys/arch/amd64/conf/Makefile.amd64
@@ -1,4 +1,4 @@
# $NetBSD: Makefile.amd64,v 1.71 2018/06/02 15:09:37 christos Exp $
# $NetBSD: Makefile.amd64,v 1.72 2018/08/20 15:04:51 maxv Exp $

# Makefile for NetBSD
#
Expand Down Expand Up @@ -49,6 +49,11 @@ CFLAGS+= -mindirect-branch=thunk-inline
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
.endif

##
## (3) libkern and compat
##
Expand Down
3 changes: 2 additions & 1 deletion sys/arch/amd64/conf/files.amd64
@@ -1,4 +1,4 @@
# $NetBSD: files.amd64,v 1.105 2018/07/13 09:37:32 maxv Exp $
# $NetBSD: files.amd64,v 1.106 2018/08/20 15:04:51 maxv Exp $
#
# new style config file for amd64 architecture
#
Expand Down Expand Up @@ -39,6 +39,7 @@ 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
Expand Down
6 changes: 5 additions & 1 deletion sys/arch/amd64/conf/kern.ldscript
@@ -1,4 +1,4 @@
/* $NetBSD: kern.ldscript,v 1.26 2018/01/21 11:21:40 maxv Exp $ */
/* $NetBSD: kern.ldscript,v 1.27 2018/08/20 15:04:51 maxv Exp $ */

#include "assym.h"

Expand Down Expand Up @@ -48,6 +48,10 @@ SECTIONS
{
*(.rodata)
*(.rodata.*)
. = ALIGN(COHERENCY_UNIT);
__CTOR_LIST__ = .;
*(.ctors)
__CTOR_END__ = .;
}

. = ALIGN(__LARGE_PAGE_SIZE);
Expand Down
8 changes: 7 additions & 1 deletion sys/arch/amd64/include/pmap.h
@@ -1,4 +1,4 @@
/* $NetBSD: pmap.h,v 1.54 2018/08/17 14:39:51 maxv Exp $ */
/* $NetBSD: pmap.h,v 1.55 2018/08/20 15:04:51 maxv Exp $ */

/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
Expand Down Expand Up @@ -67,6 +67,7 @@

#if defined(_KERNEL_OPT)
#include "opt_xen.h"
#include "opt_kasan.h"
#endif

#include <sys/atomic.h>
Expand All @@ -91,6 +92,11 @@
/* XXXfvdl this one's not right. */
#define VA_SIGN_POS(va) ((va) & ~VA_SIGN_MASK)

#ifdef KASAN
#define L4_SLOT_KASAN 256
#define NL4_SLOT_KASAN 32
#endif

#ifndef XEN
#define L4_SLOT_PTE slotspace.area[SLAREA_PTE].sslot
#else
Expand Down
5 changes: 4 additions & 1 deletion sys/arch/amd64/include/types.h
@@ -1,4 +1,4 @@
/* $NetBSD: types.h,v 1.56 2018/07/12 10:46:41 maxv Exp $ */
/* $NetBSD: types.h,v 1.57 2018/08/20 15:04:51 maxv Exp $ */

/*-
* Copyright (c) 1990 The Regents of the University of California.
Expand Down Expand Up @@ -99,11 +99,14 @@ typedef unsigned char __cpu_simple_lock_nv_t;
#define __HAVE_RAS

#include "opt_xen.h"
#include "opt_kasan.h"
#if defined(__x86_64__) && !defined(XEN)
#if !defined(KASAN)
#define __HAVE_PCPU_AREA 1
#define __HAVE_DIRECT_MAP 1
#define __HAVE_MM_MD_DIRECT_MAPPED_IO
#define __HAVE_MM_MD_DIRECT_MAPPED_PHYS
#endif
#if !defined(NO_PCI_MSI_MSIX)
#define __HAVE_PCI_MSI_MSIX
#endif
Expand Down
9 changes: 6 additions & 3 deletions sys/arch/x86/include/pmap.h
@@ -1,4 +1,4 @@
/* $NetBSD: pmap.h,v 1.84 2018/08/12 13:31:16 maxv Exp $ */
/* $NetBSD: pmap.h,v 1.85 2018/08/20 15:04:52 maxv Exp $ */

/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
Expand Down Expand Up @@ -161,8 +161,9 @@ struct bootspace {
#define SLAREA_PCPU 4
#define SLAREA_DMAP 5
#define SLAREA_HYPV 6
#define SLAREA_KERN 7
#define SLSPACE_NAREAS 8
#define SLAREA_ASAN 7
#define SLAREA_KERN 8
#define SLSPACE_NAREAS 9

struct slotspace {
struct {
Expand Down Expand Up @@ -552,6 +553,8 @@ int pmap_enter_ma(struct pmap *, vaddr_t, paddr_t, paddr_t,
bool pmap_extract_ma(pmap_t, vaddr_t, paddr_t *);
void pmap_free_ptps(struct vm_page *);

paddr_t pmap_get_physpage(void);

/*
* Hooks for the pool allocator.
*/
Expand Down
19 changes: 14 additions & 5 deletions sys/arch/x86/x86/pmap.c
@@ -1,4 +1,4 @@
/* $NetBSD: pmap.c,v 1.303 2018/08/18 08:45:55 maxv Exp $ */
/* $NetBSD: pmap.c,v 1.304 2018/08/20 15:04:52 maxv Exp $ */

/*
* Copyright (c) 2008, 2010, 2016, 2017 The NetBSD Foundation, Inc.
Expand Down Expand Up @@ -157,13 +157,14 @@
*/

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.303 2018/08/18 08:45:55 maxv Exp $");
__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.304 2018/08/20 15:04:52 maxv Exp $");

#include "opt_user_ldt.h"
#include "opt_lockdebug.h"
#include "opt_multiprocessor.h"
#include "opt_xen.h"
#include "opt_svs.h"
#include "opt_kasan.h"

#include <sys/param.h>
#include <sys/systm.h>
Expand Down Expand Up @@ -570,7 +571,6 @@ static bool pmap_remove_pte(struct pmap *, struct vm_page *, pt_entry_t *,
static void pmap_remove_ptes(struct pmap *, struct vm_page *, vaddr_t, vaddr_t,
vaddr_t, struct pv_entry **);

static paddr_t pmap_get_physpage(void);
static void pmap_alloc_level(struct pmap *, vaddr_t, long *);

static void pmap_reactivate(struct pmap *);
Expand Down Expand Up @@ -1386,7 +1386,7 @@ pmap_pagetree_nentries_range(vaddr_t startva, vaddr_t endva, size_t pgsz)
}
#endif

#if defined(__HAVE_DIRECT_MAP)
#if defined(__HAVE_DIRECT_MAP) || defined(KASAN)
static inline void
slotspace_copy(int type, pd_entry_t *dst, pd_entry_t *src)
{
Expand Down Expand Up @@ -2377,6 +2377,9 @@ pmap_pdp_ctor(void *arg, void *v, int flags)
#ifdef __HAVE_DIRECT_MAP
slotspace_copy(SLAREA_DMAP, pdir, PDP_BASE);
#endif
#ifdef KASAN
slotspace_copy(SLAREA_ASAN, pdir, PDP_BASE);
#endif
#endif /* XEN && __x86_64__*/

#ifdef XEN
Expand Down Expand Up @@ -4470,7 +4473,7 @@ pmap_enter_ma(struct pmap *pmap, vaddr_t va, paddr_t ma, paddr_t pa,
return error;
}

static paddr_t
paddr_t
pmap_get_physpage(void)
{
struct vm_page *ptp;
Expand Down Expand Up @@ -4649,6 +4652,12 @@ 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

pmap_alloc_level(cpm, pmap_maxkvaddr, needed_kptp);

/*
Expand Down
3 changes: 2 additions & 1 deletion sys/conf/files
@@ -1,4 +1,4 @@
# $NetBSD: files,v 1.1203 2018/08/14 14:49:13 maxv Exp $
# $NetBSD: files,v 1.1204 2018/08/20 15:04:52 maxv Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93

version 20171118
Expand Down Expand Up @@ -29,6 +29,7 @@ defflag KEYLOCK
defparam opt_syslimits.h CHILD_MAX OPEN_MAX
defflag opt_diagnostic.h _DIAGNOSTIC
defflag GPROF
defflag KASAN

defparam opt_copy_symtab.h makeoptions_COPY_SYMTAB

Expand Down
25 changes: 23 additions & 2 deletions sys/kern/kern_malloc.c
@@ -1,4 +1,4 @@
/* $NetBSD: kern_malloc.c,v 1.147 2018/08/20 11:46:44 maxv Exp $ */
/* $NetBSD: kern_malloc.c,v 1.148 2018/08/20 15:04:52 maxv Exp $ */

/*
* Copyright (c) 1987, 1991, 1993
Expand Down Expand Up @@ -70,12 +70,18 @@
*/

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_malloc.c,v 1.147 2018/08/20 11:46:44 maxv Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_malloc.c,v 1.148 2018/08/20 15:04:52 maxv Exp $");

#include "opt_kasan.h"

#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/kmem.h>

#ifdef KASAN
#include <sys/asan.h>
#endif

/*
* Built-in malloc types. Note: ought to be removed.
*/
Expand All @@ -100,10 +106,17 @@ void *
kern_malloc(unsigned long size, int flags)
{
const int kmflags = (flags & M_NOWAIT) ? KM_NOSLEEP : KM_SLEEP;
#ifdef KASAN
size_t origsize = size;
#endif
size_t allocsize, hdroffset;
struct malloc_header *mh;
void *p;

#ifdef KASAN
kasan_add_redzone(&size);
#endif

if (size >= PAGE_SIZE) {
if (size > (ULONG_MAX-PAGE_SIZE))
allocsize = ULONG_MAX; /* this will fail later */
Expand All @@ -126,6 +139,10 @@ kern_malloc(unsigned long size, int flags)
mh->mh_size = allocsize - hdroffset;
mh++;

#ifdef KASAN
kasan_alloc(mh, origsize, size);
#endif

return mh;
}

Expand All @@ -137,6 +154,10 @@ kern_free(void *addr)
mh = addr;
mh--;

#ifdef KASAN
kasan_free(addr, mh->mh_size);
#endif

if (mh->mh_size >= PAGE_SIZE + sizeof(struct malloc_header))
kmem_intr_free((char *)addr - PAGE_SIZE,
mh->mh_size + PAGE_SIZE - sizeof(struct malloc_header));
Expand Down

0 comments on commit ea95040

Please sign in to comment.