lkl: add KASAN support

To enable KASAN support the kasan=yes parameters should be passed to
the host build, e.g.:

make -C tools/lkl kasan=yes

Signed-off-by: Eugene Rodionov <rodionov@google.com>
Signed-off-by: Octavian Purdila <tavip@google.com>
This commit is contained in:
Eugene Rodionov
2022-11-22 13:07:00 +00:00
committed by Octavian Purdila
parent 7deea5c421
commit facd006081
10 changed files with 129 additions and 5 deletions

View File

@@ -40,6 +40,7 @@ config LKL
select UACCESS_MEMCPY
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select HAVE_ARCH_KASAN
config OUTPUT_FORMAT
string "Output format"
@@ -105,3 +106,13 @@ config RAID6_PQ_BENCHMARK
config STACKTRACE_SUPPORT
def_bool y
if KASAN
config KASAN_SHADOW_OFFSET
hex "KASAN shadow offset"
default "0"
config KASAN_SHADOW_SIZE
hex "KASAN shadow size"
default "0"
endif

View File

@@ -0,0 +1,36 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_LKL_KASAN_H
#define _ASM_LKL_KASAN_H
#ifdef CONFIG_KASAN
#include <linux/const.h>
#include <linux/pgtable.h>
#define KASAN_SHADOW_OFFSET _AC(CONFIG_KASAN_SHADOW_OFFSET, UL)
#define KASAN_SHADOW_SIZE _AC(CONFIG_KASAN_SHADOW_SIZE, UL)
#define KASAN_SHADOW_SCALE_SHIFT 3
#define KASAN_SHADOW_START KASAN_SHADOW_OFFSET
#define KASAN_SHADOW_END (KASAN_SHADOW_START + KASAN_SHADOW_SIZE)
extern int kasan_init(void);
extern int kasan_cleanup(void);
extern void kasan_unpoison_stack(void);
#else
static inline int kasan_init(void)
{
return 0;
}
static inline int kasan_cleanup(void)
{
return 0;
}
static inline void kasan_unpoison_stack(void)
{
}
#endif
#endif

View File

@@ -1,15 +1,13 @@
#ifndef _LKL_PGTABLE_H
#define _LKL_PGTABLE_H
#include <asm-generic/pgtable-nopud.h>
/*
* (C) Copyright 2000-2002, Greg Ungerer <gerg@snapgear.com>
*/
#include <linux/slab.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm-generic/pgtable-nopud.h>
#include <asm/processor.h>
#include <asm/io.h>
#define pgd_present(pgd) (1)
@@ -51,4 +49,7 @@ extern void *empty_zero_page;
#define KMAP_START 0
#define KMAP_END 0xffffffff
#define PTRS_PER_PTE 0
#define PTRS_PER_PMD 0
#endif

View File

@@ -2,6 +2,7 @@
#define _ASM_LKL_SCHED_H
#include <linux/sched.h>
#include <asm/kasan.h>
#include <uapi/asm/host_ops.h>
static inline void thread_sched_jb(void)
@@ -11,6 +12,11 @@ static inline void thread_sched_jb(void)
set_current_state(TASK_UNINTERRUPTIBLE);
lkl_ops->jmp_buf_set(&current_thread_info()->sched_jb,
schedule);
/*
* The previous call to setjmp/longjmp won't unwind the stack
* and, as a result, shadow memory will remain poisoned.
*/
kasan_unpoison_stack();
} else {
lkl_bug("thread_sched_jb() can be used only for host task");
}

View File

@@ -1,4 +1,7 @@
extra-y := vmlinux.lds
KASAN_SANITIZE_init.o := n
KASAN_SANITIZE_stacktrace.o := n
obj-y = setup.o threads.o irq.o time.o syscalls.o misc.o console.o \
syscalls_32.o cpu.o init.o stacktrace.o

View File

@@ -1,12 +1,17 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <asm/host_ops.h>
#include <asm/kasan.h>
int lkl_init(struct lkl_host_operations *ops)
{
lkl_ops = ops;
return kasan_init();
}
void lkl_cleanup(void)
{
if (kasan_cleanup() < 0)
lkl_printf("kasan: failed to cleanup\n");
}

View File

@@ -111,8 +111,10 @@ struct task_struct *__switch_to(struct task_struct *prev,
lkl_ops->sem_down(_prev->sched_sem);
}
if (_prev->dead)
if (_prev->dead) {
kasan_unpoison_stack();
lkl_ops->thread_exit();
}
return abs_prev;
}

View File

@@ -1 +1,5 @@
KASAN_SANITIZE_kasan.o := n
obj-y = bootmem.o
obj-$(CONFIG_KASAN) += kasan.o

38
arch/lkl/mm/kasan.c Normal file
View File

@@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/init_task.h>
#include <linux/kasan.h>
#include <asm/host_ops.h>
void kasan_unpoison_stack(void)
{
void *stack = NULL;
unsigned long stack_size;
if (lkl_ops->thread_stack)
stack = lkl_ops->thread_stack(&stack_size);
if (stack)
kasan_unpoison_range(stack, stack_size);
}
int kasan_cleanup(void)
{
return lkl_ops->munmap((void *)KASAN_SHADOW_OFFSET, KASAN_SHADOW_SIZE);
}
int kasan_init(void)
{
void *offset = (void *)KASAN_SHADOW_OFFSET;
int prot = LKL_PROT_READ | LKL_PROT_WRITE;
/* reserve address range for KASAN shadow memory */
if (lkl_ops->mmap(offset, KASAN_SHADOW_SIZE, prot) != offset) {
lkl_printf("kasan: failed to map shadow memory\n");
return -EFAULT;
}
init_task.kasan_depth = 0;
pr_info("KernelAddressSanitizer initialized\n");
return 0;
}

View File

@@ -1,4 +1,5 @@
POSIX_HOSTS=elf64 elf32
KASAN_HOSTS=elf64-x86-64
NT_HOSTS=pe
define set_autoconf_var
@@ -117,6 +118,22 @@ define 64bit_host
$(call set_kernel_config,64BIT,y)
endef
define kasan_x86_64
$(call set_autoconf_var,KASAN_SHADOW_OFFSET,0x0000200000000000)
$(call set_kernel_config,KASAN_SHADOW_OFFSET,0x0000200000000000)
$(call set_autoconf_var,KASAN_SHADOW_SIZE,0x0000100000000000)
$(call set_kernel_config,KASAN_SHADOW_SIZE,0x0000100000000000)
endef
define kasan_enable
$(call set_autoconf_var,KASAN,y)
$(call set_kernel_config,KASAN,y)
# default is 20 which should be 1MB but observed 8MB of reserved
# memory - half of what we use
$(call set_kernel_config,STACK_HASH_ORDER,12)
$(if $(filter $(1),elf64-x86-64),$(call kasan_x86_64))
endef
define do_autoconf
export CROSS_COMPILE := $(CROSS_COMPILE)
export CC := $(CROSS_COMPILE)gcc
@@ -131,6 +148,7 @@ define do_autoconf
$(if $(filter $(EXEC_FMT),elf64-s390),$(call s390_host))
$(if $(filter $(EXEC_FMT),$(POSIX_HOSTS)),$(call posix_host,$(LD_FMT)))
$(if $(filter $(EXEC_FMT),$(NT_HOSTS)),$(call nt_host,$(LD_FMT)))
$(if $(and $(filter yes,$(kasan)),$(filter $(LD_FMT),$(KASAN_HOSTS))),$(call kasan_enable,$(LD_FMT)))
endef
export do_autoconf