Commit 5b301409 authored by Patricia Alfonso's avatar Patricia Alfonso Committed by Richard Weinberger
Browse files

UML: add support for KASAN under x86_64



Make KASAN run on User Mode Linux on x86_64.

The UML-specific KASAN initializer uses mmap to map the ~16TB of shadow
memory to the location defined by KASAN_SHADOW_OFFSET.  kasan_init()
utilizes constructors to initialize KASAN before main().

The location of the KASAN shadow memory, starting at
KASAN_SHADOW_OFFSET, can be configured using the KASAN_SHADOW_OFFSET
option. The default location of this offset is 0x100000000000, which
keeps it out-of-the-way even on UML setups with more "physical" memory.

For low-memory setups, 0x7fff8000 can be used instead, which fits in an
immediate and is therefore faster, as suggested by Dmitry Vyukov. There
is usually enough free space at this location; however, it is a config
option so that it can be easily changed if needed.

Note that, unlike KASAN on other architectures, vmalloc allocations
still use the shadow memory allocated upfront, rather than allocating
and free-ing it per-vmalloc allocation.

If another architecture chooses to go down the same path, we should
replace the checks for CONFIG_UML with something more generic, such
as:
- A CONFIG_KASAN_NO_SHADOW_ALLOC option, which architectures could set
- or, a way of having architecture-specific versions of these vmalloc
  and module shadow memory allocation options.

Also note that, while UML supports both KASAN in inline mode
(CONFIG_KASAN_INLINE) and static linking (CONFIG_STATIC_LINK), it does
not support both at the same time.

Signed-off-by: default avatarPatricia Alfonso <trishalfonso@google.com>
Co-developed-by: default avatarVincent Whitchurch <vincent.whitchurch@axis.com>
Signed-off-by: default avatarVincent Whitchurch <vincent.whitchurch@axis.com>
Signed-off-by: default avatarDavid Gow <davidgow@google.com>
Reviewed-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Reviewed-by: default avatarDmitry Vyukov <dvyukov@google.com>
Reviewed-by: default avatarAndrey Konovalov <andreyknvl@gmail.com>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent 335e52c2
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@ config UML
	select ARCH_HAS_STRNLEN_USER
	select ARCH_NO_PREEMPT
	select HAVE_ARCH_AUDITSYSCALL
	select HAVE_ARCH_KASAN if X86_64
	select HAVE_ARCH_KASAN_VMALLOC if HAVE_ARCH_KASAN
	select HAVE_ARCH_SECCOMP_FILTER
	select HAVE_ASM_MODVERSIONS
	select HAVE_UID16
@@ -219,6 +221,19 @@ config UML_TIME_TRAVEL_SUPPORT

	  It is safe to say Y, but you probably don't need this.

config KASAN_SHADOW_OFFSET
	hex
	depends on KASAN
	default 0x100000000000
	help
	  This is the offset at which the ~16TB of shadow memory is
	  mapped and used by KASAN for memory debugging. This can be any
	  address that has at least KASAN_SHADOW_SIZE (total address space divided
	  by 8) amount of space so that the KASAN shadow memory does not conflict
	  with anything. The default is 0x100000000000, which works even if mem is
	  set to a large value. On low-memory systems, try 0x7fff8000, as it fits
	  into the immediate of most instructions, improving performance.

endmenu

source "arch/um/drivers/Kconfig"
+2 −0
Original line number Diff line number Diff line
@@ -83,6 +83,8 @@
  }
  .init_array : {
	__init_array_start = .;
	*(.kasan_init)
	*(.init_array.*)
	*(.init_array)
	__init_array_end = .;
  }
+37 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_UM_KASAN_H
#define __ASM_UM_KASAN_H

#include <linux/init.h>
#include <linux/const.h>

#define KASAN_SHADOW_OFFSET _AC(CONFIG_KASAN_SHADOW_OFFSET, UL)

/* used in kasan_mem_to_shadow to divide by 8 */
#define KASAN_SHADOW_SCALE_SHIFT 3

#ifdef CONFIG_X86_64
#define KASAN_HOST_USER_SPACE_END_ADDR 0x00007fffffffffffUL
/* KASAN_SHADOW_SIZE is the size of total address space divided by 8 */
#define KASAN_SHADOW_SIZE ((KASAN_HOST_USER_SPACE_END_ADDR + 1) >> \
			KASAN_SHADOW_SCALE_SHIFT)
#else
#error "KASAN_SHADOW_SIZE is not defined for this sub-architecture"
#endif /* CONFIG_X86_64 */

#define KASAN_SHADOW_START (KASAN_SHADOW_OFFSET)
#define KASAN_SHADOW_END (KASAN_SHADOW_START + KASAN_SHADOW_SIZE)

#ifdef CONFIG_KASAN
void kasan_init(void);
void kasan_map_memory(void *start, unsigned long len);
extern int kasan_um_is_ready;

#ifdef CONFIG_STATIC_LINK
#define kasan_arch_is_ready() (kasan_um_is_ready)
#endif
#else
static inline void kasan_init(void) { }
#endif /* CONFIG_KASAN */

#endif /* __ASM_UM_KASAN_H */
+5 −1
Original line number Diff line number Diff line
@@ -109,7 +109,11 @@ SECTIONS
     be empty, which isn't pretty.  */
  . = ALIGN(32 / 8);
  .preinit_array     : { *(.preinit_array) }
  .init_array     : { *(.init_array) }
  .init_array     : {
    *(.kasan_init)
    *(.init_array.*)
    *(.init_array)
  }
  .fini_array     : { *(.fini_array) }
  .data           : {
    INIT_TASK_DATA(KERNEL_STACK_SIZE)
+19 −0
Original line number Diff line number Diff line
@@ -18,6 +18,25 @@
#include <kern_util.h>
#include <mem_user.h>
#include <os.h>
#include <linux/sched/task.h>

#ifdef CONFIG_KASAN
int kasan_um_is_ready;
void kasan_init(void)
{
	/*
	 * kasan_map_memory will map all of the required address space and
	 * the host machine will allocate physical memory as necessary.
	 */
	kasan_map_memory((void *)KASAN_SHADOW_START, KASAN_SHADOW_SIZE);
	init_task.kasan_depth = 0;
	kasan_um_is_ready = true;
}

static void (*kasan_init_ptr)(void)
__section(".kasan_init") __used
= kasan_init;
#endif

/* allocated in paging_init, zeroed in mem_init, and unchanged thereafter */
unsigned long *empty_zero_page = NULL;
Loading