This pull request contains the following changes for UML:

- KASAN support for x86_64
 - noreboot command line option, just like qemu's -no-reboot
 - Various fixes and cleanups
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEdgfidid8lnn52cLTZvlZhesYu8EFAmLteZYACgkQZvlZhesY
 u8F8bRAA2806QUzysg3Nj1AKPiTOj47TuluGu4SXytB0usQgYK/n3Fxr36ULJAOJ
 3qZWf2fsAkBLvgX9Sw2QFGfulrpfKnLeTdBXSEbWYWhZ0ZoaEJztKmtfH02kRDOW
 POedQT5FXMDVjGQdLC7Ycp+WyjaUwrccZ+KRkGWmlr7vNFlxcTlEqBb13mgLdjkY
 ep8X+SgmAcdvWBd/os+nNn9Al6TbFd4XQCok82DtNrv0ggwXnVPov/ArvZvvn2Oj
 F028X77180rbrGV+ZnDkV1KSv/ccT5EFebJkfEEcYVjre8o0QoPQmh2tFqXN0d83
 2WpIOb1+mQL0VClpC4hKbScpIB5tw8vIHsUT+ifloIgY/puhezx6aWm0TKSA+aTM
 WitJl1Nf4uNu1rqkBkn9o3VK8CYokTALQIRexHCzvZ70CSxmFbR7EVRSTf7Rr690
 Oq7StHagfuTJpddh0wQwaMorIH4s0/bpPoA6m4OhwlppnCpY0Hfl3+AKluNRUtH6
 lPeQwfxhd/LKqYW0COElEnReDLzer82kUx/keVyxVINqxpm6YTHVtOgtMCEuVNXg
 GbS8PFCW2mIP8Is6HJavZYCzG8vnz3wZ9GENujanwLemiIJfINDauybu+nNsE5pO
 7v12vWeZ0x2HGM/cFxODrpp4xAkdq8BBLap8/aXB8uJFagmYyhs=
 =f3Bh
 -----END PGP SIGNATURE-----

Merge tag 'for-linus-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml

Pull UML updates from Richard Weinberger:

 - KASAN support for x86_64

 - noreboot command line option, just like qemu's -no-reboot

 - Various fixes and cleanups

* tag 'for-linus-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml:
  um: include sys/types.h for size_t
  um: Replace to_phys() and to_virt() with less generic function names
  um: Add missing apply_returns()
  um: add "noreboot" command line option for PANIC_TIMEOUT=-1 setups
  um: include linux/stddef.h for __always_inline
  UML: add support for KASAN under x86_64
  mm: Add PAGE_ALIGN_DOWN macro
  um: random: Don't initialise hwrng struct with zero
  um: remove unused mm_copy_segments
  um: remove unused variable
  um: Remove straying parenthesis
  um: x86: print RIP with symbol
  arch: um: Fix build for statically linked UML w/ constructors
  x86/um: Kconfig: Fix indentation
  um/drivers: Kconfig: Fix indentation
  um: Kconfig: Fix indentation
This commit is contained in:
Linus Torvalds 2022-08-05 14:03:11 -07:00
commit 79b7e67bb9
23 changed files with 196 additions and 53 deletions

View File

@ -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
@ -82,7 +84,7 @@ config ARCH_HAS_CACHE_LINE_SIZE
source "arch/$(HEADER_ARCH)/um/Kconfig"
config MAY_HAVE_RUNTIME_DEPS
bool
bool
config STATIC_LINK
bool "Force a static link"
@ -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"

View File

@ -251,37 +251,37 @@ config UML_NET_VECTOR
depends on UML_NET
select MAY_HAVE_RUNTIME_DEPS
help
This User-Mode Linux network driver uses multi-message send
and receive functions. The host running the UML guest must have
a linux kernel version above 3.0 and a libc version > 2.13.
This driver provides tap, raw, gre and l2tpv3 network transports
with up to 4 times higher network throughput than the UML network
drivers.
This User-Mode Linux network driver uses multi-message send
and receive functions. The host running the UML guest must have
a linux kernel version above 3.0 and a libc version > 2.13.
This driver provides tap, raw, gre and l2tpv3 network transports
with up to 4 times higher network throughput than the UML network
drivers.
config UML_NET_VDE
bool "VDE transport (obsolete)"
depends on UML_NET
select MAY_HAVE_RUNTIME_DEPS
help
This User-Mode Linux network transport allows one or more running
UMLs on a single host to communicate with each other and also
with the rest of the world using Virtual Distributed Ethernet,
an improved fork of uml_switch.
This User-Mode Linux network transport allows one or more running
UMLs on a single host to communicate with each other and also
with the rest of the world using Virtual Distributed Ethernet,
an improved fork of uml_switch.
You must have libvdeplug installed in order to build the vde
transport into UML.
You must have libvdeplug installed in order to build the vde
transport into UML.
To use this form of networking, you will need to run vde_switch
on the host.
To use this form of networking, you will need to run vde_switch
on the host.
For more information, see <http://wiki.virtualsquare.org/>
That site has a good overview of what VDE is and also examples
of the UML command line to use to enable VDE networking.
For more information, see <http://wiki.virtualsquare.org/>
That site has a good overview of what VDE is and also examples
of the UML command line to use to enable VDE networking.
NOTE: THIS TRANSPORT IS DEPRECATED AND WILL BE REMOVED SOON!!! Please
migrate to UML_NET_VECTOR.
NOTE: THIS TRANSPORT IS DEPRECATED AND WILL BE REMOVED SOON!!! Please
migrate to UML_NET_VECTOR.
If unsure, say N.
If unsure, say N.
config UML_NET_MCAST
bool "Multicast transport (obsolete)"
@ -311,19 +311,19 @@ config UML_NET_PCAP
depends on UML_NET
select MAY_HAVE_RUNTIME_DEPS
help
The pcap transport makes a pcap packet stream on the host look
like an ethernet device inside UML. This is useful for making
UML act as a network monitor for the host. You must have libcap
installed in order to build the pcap transport into UML.
The pcap transport makes a pcap packet stream on the host look
like an ethernet device inside UML. This is useful for making
UML act as a network monitor for the host. You must have libcap
installed in order to build the pcap transport into UML.
For more information, see
<http://user-mode-linux.sourceforge.net/old/networking.html> That site
has examples of the UML command line to use to enable this option.
NOTE: THIS TRANSPORT IS DEPRECATED AND WILL BE REMOVED SOON!!! Please
migrate to UML_NET_VECTOR.
NOTE: THIS TRANSPORT IS DEPRECATED AND WILL BE REMOVED SOON!!! Please
migrate to UML_NET_VECTOR.
If unsure, say N.
If unsure, say N.
config UML_NET_SLIRP
bool "SLiRP transport (obsolete)"

View File

@ -28,7 +28,7 @@
* protects against a module being loaded twice at the same time.
*/
static int random_fd = -1;
static struct hwrng hwrng = { 0, };
static struct hwrng hwrng;
static DECLARE_COMPLETION(have_data);
static int rng_dev_read(struct hwrng *rng, void *buf, size_t max, bool block)

View File

@ -83,6 +83,8 @@
}
.init_array : {
__init_array_start = .;
*(.kasan_init)
*(.init_array.*)
*(.init_array)
__init_array_end = .;
}

View File

@ -0,0 +1,37 @@
/* 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 */

View File

@ -59,11 +59,6 @@ static inline void release_thread(struct task_struct *task)
{
}
static inline void mm_copy_segments(struct mm_struct *from_mm,
struct mm_struct *new_mm)
{
}
/*
* User space process size: 3GB (default).
*/

View File

@ -18,7 +18,7 @@
#undef XOR_SELECT_TEMPLATE
/* pick an arbitrary one - measuring isn't possible with inf-cpu */
#define XOR_SELECT_TEMPLATE(x) \
(time_travel_mode == TT_MODE_INFCPU ? TT_CPU_INF_XOR_DEFAULT : x))
(time_travel_mode == TT_MODE_INFCPU ? TT_CPU_INF_XOR_DEFAULT : x)
#endif
#endif

View File

@ -16,11 +16,12 @@
*/
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
/* This is to get size_t */
/* This is to get size_t and NULL */
#ifndef __UM_HOST__
#include <linux/types.h>
#else
#include <stddef.h>
#include <sys/types.h>
#endif
extern void panic(const char *fmt, ...)

View File

@ -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)

View File

@ -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;

View File

@ -27,7 +27,7 @@ void dump_trace(struct task_struct *tsk,
frame = (struct stack_frame *)bp;
while (((long) sp & (THREAD_SIZE-1)) != 0) {
addr = *sp;
addr = READ_ONCE_NOCHECK(*sp);
if (__kernel_text_address(addr)) {
reliable = 0;
if ((unsigned long) sp == bp + sizeof(long)) {

View File

@ -95,6 +95,7 @@ SECTIONS
}
.got : { *(.got.plt) *(.got) }
.eh_frame : { KEEP (*(.eh_frame)) }
.dynamic : { *(.dynamic) }
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }

View File

@ -17,6 +17,28 @@
#include <init.h>
#include <os.h>
/*
* kasan_map_memory - maps memory from @start with a size of @len.
* The allocated memory is filled with zeroes upon success.
* @start: the start address of the memory to be mapped
* @len: the length of the memory to be mapped
*
* This function is used to map shadow memory for KASAN in uml
*/
void kasan_map_memory(void *start, size_t len)
{
if (mmap(start,
len,
PROT_READ|PROT_WRITE,
MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE,
-1,
0) == MAP_FAILED) {
os_info("Couldn't allocate shadow memory: %s\n.",
strerror(errno));
exit(1);
}
}
/* Set by make_tempfile() during early boot. */
static char *tempdir = NULL;

View File

@ -5,6 +5,7 @@
*/
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <sched.h>
#include <errno.h>
@ -707,10 +708,24 @@ void halt_skas(void)
UML_LONGJMP(&initial_jmpbuf, INIT_JMP_HALT);
}
static bool noreboot;
static int __init noreboot_cmd_param(char *str, int *add)
{
noreboot = true;
return 0;
}
__uml_setup("noreboot", noreboot_cmd_param,
"noreboot\n"
" Rather than rebooting, exit always, akin to QEMU's -no-reboot option.\n"
" This is useful if you're using CONFIG_PANIC_TIMEOUT in order to catch\n"
" crashes in CI\n");
void reboot_skas(void)
{
block_signals_trace();
UML_LONGJMP(&initial_jmpbuf, INIT_JMP_REBOOT);
UML_LONGJMP(&initial_jmpbuf, noreboot ? INIT_JMP_HALT : INIT_JMP_REBOOT);
}
void __switch_mm(struct mm_id *mm_idp)

View File

@ -136,7 +136,7 @@ out:
static inline int is_umdir_used(char *dir)
{
char pid[sizeof("nnnnnnnnn")], *end, *file;
int dead, fd, p, n, err;
int fd, p, n, err;
size_t filelen = strlen(dir) + sizeof("/pid") + 1;
file = malloc(filelen);
@ -145,7 +145,6 @@ static inline int is_umdir_used(char *dir)
snprintf(file, filelen, "%s/pid", dir);
dead = 0;
fd = open(file, O_RDONLY);
if (fd < 0) {
fd = -errno;

View File

@ -27,10 +27,10 @@ EXPORT_SYMBOL(strstr);
#ifndef __x86_64__
extern void *memcpy(void *, const void *, size_t);
EXPORT_SYMBOL(memcpy);
#endif
EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(memset);
#endif
EXPORT_SYMBOL(printf);
/* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms.

View File

@ -32,12 +32,12 @@ config 3_LEVEL_PGTABLES
bool "Three-level pagetables" if !64BIT
default 64BIT
help
Three-level pagetables will let UML have more than 4G of physical
memory. All the memory that can't be mapped directly will be treated
as high memory.
Three-level pagetables will let UML have more than 4G of physical
memory. All the memory that can't be mapped directly will be treated
as high memory.
However, this it experimental on 32-bit architectures, so if unsure say
N (on x86-64 it's automatically enabled, instead, as it's safe there).
However, this it experimental on 32-bit architectures, so if unsure say
N (on x86-64 it's automatically enabled, instead, as it's safe there).
config ARCH_HAS_SC_SIGNALS
def_bool !64BIT

View File

@ -28,7 +28,8 @@ else
obj-y += syscalls_64.o vdso/
subarch-y = ../lib/csum-partial_64.o ../lib/memcpy_64.o ../entry/thunk_64.o
subarch-y = ../lib/csum-partial_64.o ../lib/memcpy_64.o ../entry/thunk_64.o \
../lib/memmove_64.o ../lib/memset_64.o
endif

View File

@ -8,6 +8,7 @@
#include <sysdep/ptrace_user.h>
#include <generated/asm-offsets.h>
#include <linux/stddef.h>
#define STUB_MMAP_NR __NR_mmap
#define MMAP_OFFSET(o) (o)

View File

@ -19,8 +19,8 @@ void show_regs(struct pt_regs *regs)
print_modules();
printk(KERN_INFO "Pid: %d, comm: %.20s %s %s\n", task_pid_nr(current),
current->comm, print_tainted(), init_utsname()->release);
printk(KERN_INFO "RIP: %04lx:[<%016lx>]\n", PT_REGS_CS(regs) & 0xffff,
PT_REGS_IP(regs));
printk(KERN_INFO "RIP: %04lx:%pS\n", PT_REGS_CS(regs) & 0xffff,
(void *)PT_REGS_IP(regs));
printk(KERN_INFO "RSP: %016lx EFLAGS: %08lx\n", PT_REGS_SP(regs),
PT_REGS_EFLAGS(regs));
printk(KERN_INFO "RAX: %016lx RBX: %016lx RCX: %016lx\n",

View File

@ -3,6 +3,9 @@
# Building vDSO images for x86.
#
# do not instrument on vdso because KASAN is not compatible with user mode
KASAN_SANITIZE := n
# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
KCOV_INSTRUMENT := n

View File

@ -221,6 +221,9 @@ int overcommit_policy_handler(struct ctl_table *, int, void *, size_t *,
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE)
/* to align the pointer to the (prev) page boundary */
#define PAGE_ALIGN_DOWN(addr) ALIGN_DOWN(addr, PAGE_SIZE)
/* test whether an address (unsigned long or pointer) is aligned to PAGE_SIZE */
#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE)

View File

@ -295,9 +295,22 @@ int kasan_populate_vmalloc(unsigned long addr, unsigned long size)
return 0;
shadow_start = (unsigned long)kasan_mem_to_shadow((void *)addr);
shadow_start = ALIGN_DOWN(shadow_start, PAGE_SIZE);
shadow_end = (unsigned long)kasan_mem_to_shadow((void *)addr + size);
shadow_end = ALIGN(shadow_end, PAGE_SIZE);
/*
* User Mode Linux maps enough shadow memory for all of virtual memory
* at boot, so doesn't need to allocate more on vmalloc, just clear it.
*
* The remaining CONFIG_UML checks in this file exist for the same
* reason.
*/
if (IS_ENABLED(CONFIG_UML)) {
__memset((void *)shadow_start, KASAN_VMALLOC_INVALID, shadow_end - shadow_start);
return 0;
}
shadow_start = PAGE_ALIGN_DOWN(shadow_start);
shadow_end = PAGE_ALIGN(shadow_end);
ret = apply_to_page_range(&init_mm, shadow_start,
shadow_end - shadow_start,
@ -466,6 +479,10 @@ void kasan_release_vmalloc(unsigned long start, unsigned long end,
if (shadow_end > shadow_start) {
size = shadow_end - shadow_start;
if (IS_ENABLED(CONFIG_UML)) {
__memset(shadow_start, KASAN_SHADOW_INIT, shadow_end - shadow_start);
return;
}
apply_to_existing_page_range(&init_mm,
(unsigned long)shadow_start,
size, kasan_depopulate_vmalloc_pte,
@ -531,6 +548,11 @@ int kasan_alloc_module_shadow(void *addr, size_t size, gfp_t gfp_mask)
if (WARN_ON(!PAGE_ALIGNED(shadow_start)))
return -EINVAL;
if (IS_ENABLED(CONFIG_UML)) {
__memset((void *)shadow_start, KASAN_SHADOW_INIT, shadow_size);
return 0;
}
ret = __vmalloc_node_range(shadow_size, 1, shadow_start,
shadow_start + shadow_size,
GFP_KERNEL,
@ -554,6 +576,9 @@ int kasan_alloc_module_shadow(void *addr, size_t size, gfp_t gfp_mask)
void kasan_free_module_shadow(const struct vm_struct *vm)
{
if (IS_ENABLED(CONFIG_UML))
return;
if (vm->flags & VM_KASAN)
vfree(kasan_mem_to_shadow(vm->addr));
}