Skip to content

Commit 5b30140

Browse files
Patricia Alfonsorichardweinberger
authored andcommitted
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: Patricia Alfonso <[email protected]> Co-developed-by: Vincent Whitchurch <[email protected]> Signed-off-by: Vincent Whitchurch <[email protected]> Signed-off-by: David Gow <[email protected]> Reviewed-by: Johannes Berg <[email protected]> Reviewed-by: Dmitry Vyukov <[email protected]> Reviewed-by: Andrey Konovalov <[email protected]> Signed-off-by: Richard Weinberger <[email protected]>
1 parent 335e52c commit 5b30140

File tree

11 files changed

+135
-7
lines changed

11 files changed

+135
-7
lines changed

arch/um/Kconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ config UML
1212
select ARCH_HAS_STRNLEN_USER
1313
select ARCH_NO_PREEMPT
1414
select HAVE_ARCH_AUDITSYSCALL
15+
select HAVE_ARCH_KASAN if X86_64
16+
select HAVE_ARCH_KASAN_VMALLOC if HAVE_ARCH_KASAN
1517
select HAVE_ARCH_SECCOMP_FILTER
1618
select HAVE_ASM_MODVERSIONS
1719
select HAVE_UID16
@@ -219,6 +221,19 @@ config UML_TIME_TRAVEL_SUPPORT
219221

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

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

224239
source "arch/um/drivers/Kconfig"

arch/um/include/asm/common.lds.S

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@
8383
}
8484
.init_array : {
8585
__init_array_start = .;
86+
*(.kasan_init)
87+
*(.init_array.*)
8688
*(.init_array)
8789
__init_array_end = .;
8890
}

arch/um/include/asm/kasan.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef __ASM_UM_KASAN_H
3+
#define __ASM_UM_KASAN_H
4+
5+
#include <linux/init.h>
6+
#include <linux/const.h>
7+
8+
#define KASAN_SHADOW_OFFSET _AC(CONFIG_KASAN_SHADOW_OFFSET, UL)
9+
10+
/* used in kasan_mem_to_shadow to divide by 8 */
11+
#define KASAN_SHADOW_SCALE_SHIFT 3
12+
13+
#ifdef CONFIG_X86_64
14+
#define KASAN_HOST_USER_SPACE_END_ADDR 0x00007fffffffffffUL
15+
/* KASAN_SHADOW_SIZE is the size of total address space divided by 8 */
16+
#define KASAN_SHADOW_SIZE ((KASAN_HOST_USER_SPACE_END_ADDR + 1) >> \
17+
KASAN_SHADOW_SCALE_SHIFT)
18+
#else
19+
#error "KASAN_SHADOW_SIZE is not defined for this sub-architecture"
20+
#endif /* CONFIG_X86_64 */
21+
22+
#define KASAN_SHADOW_START (KASAN_SHADOW_OFFSET)
23+
#define KASAN_SHADOW_END (KASAN_SHADOW_START + KASAN_SHADOW_SIZE)
24+
25+
#ifdef CONFIG_KASAN
26+
void kasan_init(void);
27+
void kasan_map_memory(void *start, unsigned long len);
28+
extern int kasan_um_is_ready;
29+
30+
#ifdef CONFIG_STATIC_LINK
31+
#define kasan_arch_is_ready() (kasan_um_is_ready)
32+
#endif
33+
#else
34+
static inline void kasan_init(void) { }
35+
#endif /* CONFIG_KASAN */
36+
37+
#endif /* __ASM_UM_KASAN_H */

arch/um/kernel/dyn.lds.S

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,11 @@ SECTIONS
109109
be empty, which isn't pretty. */
110110
. = ALIGN(32 / 8);
111111
.preinit_array : { *(.preinit_array) }
112-
.init_array : { *(.init_array) }
112+
.init_array : {
113+
*(.kasan_init)
114+
*(.init_array.*)
115+
*(.init_array)
116+
}
113117
.fini_array : { *(.fini_array) }
114118
.data : {
115119
INIT_TASK_DATA(KERNEL_STACK_SIZE)

arch/um/kernel/mem.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,25 @@
1818
#include <kern_util.h>
1919
#include <mem_user.h>
2020
#include <os.h>
21+
#include <linux/sched/task.h>
22+
23+
#ifdef CONFIG_KASAN
24+
int kasan_um_is_ready;
25+
void kasan_init(void)
26+
{
27+
/*
28+
* kasan_map_memory will map all of the required address space and
29+
* the host machine will allocate physical memory as necessary.
30+
*/
31+
kasan_map_memory((void *)KASAN_SHADOW_START, KASAN_SHADOW_SIZE);
32+
init_task.kasan_depth = 0;
33+
kasan_um_is_ready = true;
34+
}
35+
36+
static void (*kasan_init_ptr)(void)
37+
__section(".kasan_init") __used
38+
= kasan_init;
39+
#endif
2140

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

arch/um/kernel/stacktrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ void dump_trace(struct task_struct *tsk,
2727

2828
frame = (struct stack_frame *)bp;
2929
while (((long) sp & (THREAD_SIZE-1)) != 0) {
30-
addr = *sp;
30+
addr = READ_ONCE_NOCHECK(*sp);
3131
if (__kernel_text_address(addr)) {
3232
reliable = 0;
3333
if ((unsigned long) sp == bp + sizeof(long)) {

arch/um/os-Linux/mem.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,28 @@
1717
#include <init.h>
1818
#include <os.h>
1919

20+
/*
21+
* kasan_map_memory - maps memory from @start with a size of @len.
22+
* The allocated memory is filled with zeroes upon success.
23+
* @start: the start address of the memory to be mapped
24+
* @len: the length of the memory to be mapped
25+
*
26+
* This function is used to map shadow memory for KASAN in uml
27+
*/
28+
void kasan_map_memory(void *start, size_t len)
29+
{
30+
if (mmap(start,
31+
len,
32+
PROT_READ|PROT_WRITE,
33+
MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE,
34+
-1,
35+
0) == MAP_FAILED) {
36+
os_info("Couldn't allocate shadow memory: %s\n.",
37+
strerror(errno));
38+
exit(1);
39+
}
40+
}
41+
2042
/* Set by make_tempfile() during early boot. */
2143
static char *tempdir = NULL;
2244

arch/um/os-Linux/user_syms.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ EXPORT_SYMBOL(strstr);
2727
#ifndef __x86_64__
2828
extern void *memcpy(void *, const void *, size_t);
2929
EXPORT_SYMBOL(memcpy);
30-
#endif
31-
3230
EXPORT_SYMBOL(memmove);
3331
EXPORT_SYMBOL(memset);
32+
#endif
33+
3434
EXPORT_SYMBOL(printf);
3535

3636
/* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms.

arch/x86/um/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ else
2828

2929
obj-y += syscalls_64.o vdso/
3030

31-
subarch-y = ../lib/csum-partial_64.o ../lib/memcpy_64.o ../entry/thunk_64.o
31+
subarch-y = ../lib/csum-partial_64.o ../lib/memcpy_64.o ../entry/thunk_64.o \
32+
../lib/memmove_64.o ../lib/memset_64.o
3233

3334
endif
3435

arch/x86/um/vdso/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
# Building vDSO images for x86.
44
#
55

6+
# do not instrument on vdso because KASAN is not compatible with user mode
7+
KASAN_SANITIZE := n
8+
69
# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
710
KCOV_INSTRUMENT := n
811

0 commit comments

Comments
 (0)