162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) 462306a36Sopenharmony_ci * Copyright (C) 2002- 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <stdlib.h> 862306a36Sopenharmony_ci#include <stdbool.h> 962306a36Sopenharmony_ci#include <unistd.h> 1062306a36Sopenharmony_ci#include <sched.h> 1162306a36Sopenharmony_ci#include <errno.h> 1262306a36Sopenharmony_ci#include <string.h> 1362306a36Sopenharmony_ci#include <sys/mman.h> 1462306a36Sopenharmony_ci#include <sys/wait.h> 1562306a36Sopenharmony_ci#include <asm/unistd.h> 1662306a36Sopenharmony_ci#include <as-layout.h> 1762306a36Sopenharmony_ci#include <init.h> 1862306a36Sopenharmony_ci#include <kern_util.h> 1962306a36Sopenharmony_ci#include <mem.h> 2062306a36Sopenharmony_ci#include <os.h> 2162306a36Sopenharmony_ci#include <ptrace_user.h> 2262306a36Sopenharmony_ci#include <registers.h> 2362306a36Sopenharmony_ci#include <skas.h> 2462306a36Sopenharmony_ci#include <sysdep/stub.h> 2562306a36Sopenharmony_ci#include <linux/threads.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ciint is_skas_winch(int pid, int fd, void *data) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci return pid == getpgrp(); 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic const char *ptrace_reg_name(int idx) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci#define R(n) case HOST_##n: return #n 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci switch (idx) { 3762306a36Sopenharmony_ci#ifdef __x86_64__ 3862306a36Sopenharmony_ci R(BX); 3962306a36Sopenharmony_ci R(CX); 4062306a36Sopenharmony_ci R(DI); 4162306a36Sopenharmony_ci R(SI); 4262306a36Sopenharmony_ci R(DX); 4362306a36Sopenharmony_ci R(BP); 4462306a36Sopenharmony_ci R(AX); 4562306a36Sopenharmony_ci R(R8); 4662306a36Sopenharmony_ci R(R9); 4762306a36Sopenharmony_ci R(R10); 4862306a36Sopenharmony_ci R(R11); 4962306a36Sopenharmony_ci R(R12); 5062306a36Sopenharmony_ci R(R13); 5162306a36Sopenharmony_ci R(R14); 5262306a36Sopenharmony_ci R(R15); 5362306a36Sopenharmony_ci R(ORIG_AX); 5462306a36Sopenharmony_ci R(CS); 5562306a36Sopenharmony_ci R(SS); 5662306a36Sopenharmony_ci R(EFLAGS); 5762306a36Sopenharmony_ci#elif defined(__i386__) 5862306a36Sopenharmony_ci R(IP); 5962306a36Sopenharmony_ci R(SP); 6062306a36Sopenharmony_ci R(EFLAGS); 6162306a36Sopenharmony_ci R(AX); 6262306a36Sopenharmony_ci R(BX); 6362306a36Sopenharmony_ci R(CX); 6462306a36Sopenharmony_ci R(DX); 6562306a36Sopenharmony_ci R(SI); 6662306a36Sopenharmony_ci R(DI); 6762306a36Sopenharmony_ci R(BP); 6862306a36Sopenharmony_ci R(CS); 6962306a36Sopenharmony_ci R(SS); 7062306a36Sopenharmony_ci R(DS); 7162306a36Sopenharmony_ci R(FS); 7262306a36Sopenharmony_ci R(ES); 7362306a36Sopenharmony_ci R(GS); 7462306a36Sopenharmony_ci R(ORIG_AX); 7562306a36Sopenharmony_ci#endif 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci return ""; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic int ptrace_dump_regs(int pid) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci unsigned long regs[MAX_REG_NR]; 8362306a36Sopenharmony_ci int i; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) 8662306a36Sopenharmony_ci return -errno; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci printk(UM_KERN_ERR "Stub registers -\n"); 8962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regs); i++) { 9062306a36Sopenharmony_ci const char *regname = ptrace_reg_name(i); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci printk(UM_KERN_ERR "\t%s\t(%2d): %lx\n", regname, i, regs[i]); 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return 0; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* 9962306a36Sopenharmony_ci * Signals that are OK to receive in the stub - we'll just continue it. 10062306a36Sopenharmony_ci * SIGWINCH will happen when UML is inside a detached screen. 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci#define STUB_SIG_MASK ((1 << SIGALRM) | (1 << SIGWINCH)) 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* Signals that the stub will finish with - anything else is an error */ 10562306a36Sopenharmony_ci#define STUB_DONE_MASK (1 << SIGTRAP) 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_civoid wait_stub_done(int pid) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci int n, status, err; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci while (1) { 11262306a36Sopenharmony_ci CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL)); 11362306a36Sopenharmony_ci if ((n < 0) || !WIFSTOPPED(status)) 11462306a36Sopenharmony_ci goto bad_wait; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (((1 << WSTOPSIG(status)) & STUB_SIG_MASK) == 0) 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci err = ptrace(PTRACE_CONT, pid, 0, 0); 12062306a36Sopenharmony_ci if (err) { 12162306a36Sopenharmony_ci printk(UM_KERN_ERR "%s : continue failed, errno = %d\n", 12262306a36Sopenharmony_ci __func__, errno); 12362306a36Sopenharmony_ci fatal_sigsegv(); 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0) 12862306a36Sopenharmony_ci return; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cibad_wait: 13162306a36Sopenharmony_ci err = ptrace_dump_regs(pid); 13262306a36Sopenharmony_ci if (err) 13362306a36Sopenharmony_ci printk(UM_KERN_ERR "Failed to get registers from stub, errno = %d\n", 13462306a36Sopenharmony_ci -err); 13562306a36Sopenharmony_ci printk(UM_KERN_ERR "%s : failed to wait for SIGTRAP, pid = %d, n = %d, errno = %d, status = 0x%x\n", 13662306a36Sopenharmony_ci __func__, pid, n, errno, status); 13762306a36Sopenharmony_ci fatal_sigsegv(); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ciextern unsigned long current_stub_stack(void); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic void get_skas_faultinfo(int pid, struct faultinfo *fi, unsigned long *aux_fp_regs) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci int err; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci err = get_fp_registers(pid, aux_fp_regs); 14762306a36Sopenharmony_ci if (err < 0) { 14862306a36Sopenharmony_ci printk(UM_KERN_ERR "save_fp_registers returned %d\n", 14962306a36Sopenharmony_ci err); 15062306a36Sopenharmony_ci fatal_sigsegv(); 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV); 15362306a36Sopenharmony_ci if (err) { 15462306a36Sopenharmony_ci printk(UM_KERN_ERR "Failed to continue stub, pid = %d, " 15562306a36Sopenharmony_ci "errno = %d\n", pid, errno); 15662306a36Sopenharmony_ci fatal_sigsegv(); 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci wait_stub_done(pid); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* 16162306a36Sopenharmony_ci * faultinfo is prepared by the stub_segv_handler at start of 16262306a36Sopenharmony_ci * the stub stack page. We just have to copy it. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ci memcpy(fi, (void *)current_stub_stack(), sizeof(*fi)); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci err = put_fp_registers(pid, aux_fp_regs); 16762306a36Sopenharmony_ci if (err < 0) { 16862306a36Sopenharmony_ci printk(UM_KERN_ERR "put_fp_registers returned %d\n", 16962306a36Sopenharmony_ci err); 17062306a36Sopenharmony_ci fatal_sigsegv(); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic void handle_segv(int pid, struct uml_pt_regs *regs, unsigned long *aux_fp_regs) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci get_skas_faultinfo(pid, ®s->faultinfo, aux_fp_regs); 17762306a36Sopenharmony_ci segv(regs->faultinfo, 0, 1, NULL); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/* 18162306a36Sopenharmony_ci * To use the same value of using_sysemu as the caller, ask it that value 18262306a36Sopenharmony_ci * (in local_using_sysemu 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_cistatic void handle_trap(int pid, struct uml_pt_regs *regs, 18562306a36Sopenharmony_ci int local_using_sysemu) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci int err, status; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END)) 19062306a36Sopenharmony_ci fatal_sigsegv(); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (!local_using_sysemu) 19362306a36Sopenharmony_ci { 19462306a36Sopenharmony_ci err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 19562306a36Sopenharmony_ci __NR_getpid); 19662306a36Sopenharmony_ci if (err < 0) { 19762306a36Sopenharmony_ci printk(UM_KERN_ERR "%s - nullifying syscall failed, errno = %d\n", 19862306a36Sopenharmony_ci __func__, errno); 19962306a36Sopenharmony_ci fatal_sigsegv(); 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci err = ptrace(PTRACE_SYSCALL, pid, 0, 0); 20362306a36Sopenharmony_ci if (err < 0) { 20462306a36Sopenharmony_ci printk(UM_KERN_ERR "%s - continuing to end of syscall failed, errno = %d\n", 20562306a36Sopenharmony_ci __func__, errno); 20662306a36Sopenharmony_ci fatal_sigsegv(); 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL)); 21062306a36Sopenharmony_ci if ((err < 0) || !WIFSTOPPED(status) || 21162306a36Sopenharmony_ci (WSTOPSIG(status) != SIGTRAP + 0x80)) { 21262306a36Sopenharmony_ci err = ptrace_dump_regs(pid); 21362306a36Sopenharmony_ci if (err) 21462306a36Sopenharmony_ci printk(UM_KERN_ERR "Failed to get registers from process, errno = %d\n", 21562306a36Sopenharmony_ci -err); 21662306a36Sopenharmony_ci printk(UM_KERN_ERR "%s - failed to wait at end of syscall, errno = %d, status = %d\n", 21762306a36Sopenharmony_ci __func__, errno, status); 21862306a36Sopenharmony_ci fatal_sigsegv(); 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci handle_syscall(regs); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ciextern char __syscall_stub_start[]; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/** 22862306a36Sopenharmony_ci * userspace_tramp() - userspace trampoline 22962306a36Sopenharmony_ci * @stack: pointer to the new userspace stack page, can be NULL, if? FIXME: 23062306a36Sopenharmony_ci * 23162306a36Sopenharmony_ci * The userspace trampoline is used to setup a new userspace process in start_userspace() after it was clone()'ed. 23262306a36Sopenharmony_ci * This function will run on a temporary stack page. 23362306a36Sopenharmony_ci * It ptrace()'es itself, then 23462306a36Sopenharmony_ci * Two pages are mapped into the userspace address space: 23562306a36Sopenharmony_ci * - STUB_CODE (with EXEC), which contains the skas stub code 23662306a36Sopenharmony_ci * - STUB_DATA (with R/W), which contains a data page that is used to transfer certain data between the UML userspace process and the UML kernel. 23762306a36Sopenharmony_ci * Also for the userspace process a SIGSEGV handler is installed to catch pagefaults in the userspace process. 23862306a36Sopenharmony_ci * And last the process stops itself to give control to the UML kernel for this userspace process. 23962306a36Sopenharmony_ci * 24062306a36Sopenharmony_ci * Return: Always zero, otherwise the current userspace process is ended with non null exit() call 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_cistatic int userspace_tramp(void *stack) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci void *addr; 24562306a36Sopenharmony_ci int fd; 24662306a36Sopenharmony_ci unsigned long long offset; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci ptrace(PTRACE_TRACEME, 0, 0, 0); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci signal(SIGTERM, SIG_DFL); 25162306a36Sopenharmony_ci signal(SIGWINCH, SIG_IGN); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci fd = phys_mapping(uml_to_phys(__syscall_stub_start), &offset); 25462306a36Sopenharmony_ci addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE, 25562306a36Sopenharmony_ci PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); 25662306a36Sopenharmony_ci if (addr == MAP_FAILED) { 25762306a36Sopenharmony_ci printk(UM_KERN_ERR "mapping mmap stub at 0x%lx failed, errno = %d\n", 25862306a36Sopenharmony_ci STUB_CODE, errno); 25962306a36Sopenharmony_ci exit(1); 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (stack != NULL) { 26362306a36Sopenharmony_ci fd = phys_mapping(uml_to_phys(stack), &offset); 26462306a36Sopenharmony_ci addr = mmap((void *) STUB_DATA, 26562306a36Sopenharmony_ci STUB_DATA_PAGES * UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, 26662306a36Sopenharmony_ci MAP_FIXED | MAP_SHARED, fd, offset); 26762306a36Sopenharmony_ci if (addr == MAP_FAILED) { 26862306a36Sopenharmony_ci printk(UM_KERN_ERR "mapping segfault stack at 0x%lx failed, errno = %d\n", 26962306a36Sopenharmony_ci STUB_DATA, errno); 27062306a36Sopenharmony_ci exit(1); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci if (stack != NULL) { 27462306a36Sopenharmony_ci struct sigaction sa; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci unsigned long v = STUB_CODE + 27762306a36Sopenharmony_ci (unsigned long) stub_segv_handler - 27862306a36Sopenharmony_ci (unsigned long) __syscall_stub_start; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci set_sigstack((void *) STUB_DATA, STUB_DATA_PAGES * UM_KERN_PAGE_SIZE); 28162306a36Sopenharmony_ci sigemptyset(&sa.sa_mask); 28262306a36Sopenharmony_ci sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO; 28362306a36Sopenharmony_ci sa.sa_sigaction = (void *) v; 28462306a36Sopenharmony_ci sa.sa_restorer = NULL; 28562306a36Sopenharmony_ci if (sigaction(SIGSEGV, &sa, NULL) < 0) { 28662306a36Sopenharmony_ci printk(UM_KERN_ERR "%s - setting SIGSEGV handler failed - errno = %d\n", 28762306a36Sopenharmony_ci __func__, errno); 28862306a36Sopenharmony_ci exit(1); 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci kill(os_getpid(), SIGSTOP); 29362306a36Sopenharmony_ci return 0; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ciint userspace_pid[NR_CPUS]; 29762306a36Sopenharmony_ciint kill_userspace_mm[NR_CPUS]; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/** 30062306a36Sopenharmony_ci * start_userspace() - prepare a new userspace process 30162306a36Sopenharmony_ci * @stub_stack: pointer to the stub stack. Can be NULL, if? FIXME: 30262306a36Sopenharmony_ci * 30362306a36Sopenharmony_ci * Setups a new temporary stack page that is used while userspace_tramp() runs 30462306a36Sopenharmony_ci * Clones the kernel process into a new userspace process, with FDs only. 30562306a36Sopenharmony_ci * 30662306a36Sopenharmony_ci * Return: When positive: the process id of the new userspace process, 30762306a36Sopenharmony_ci * when negative: an error number. 30862306a36Sopenharmony_ci * FIXME: can PIDs become negative?! 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ciint start_userspace(unsigned long stub_stack) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci void *stack; 31362306a36Sopenharmony_ci unsigned long sp; 31462306a36Sopenharmony_ci int pid, status, n, flags, err; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* setup a temporary stack page */ 31762306a36Sopenharmony_ci stack = mmap(NULL, UM_KERN_PAGE_SIZE, 31862306a36Sopenharmony_ci PROT_READ | PROT_WRITE | PROT_EXEC, 31962306a36Sopenharmony_ci MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 32062306a36Sopenharmony_ci if (stack == MAP_FAILED) { 32162306a36Sopenharmony_ci err = -errno; 32262306a36Sopenharmony_ci printk(UM_KERN_ERR "%s : mmap failed, errno = %d\n", 32362306a36Sopenharmony_ci __func__, errno); 32462306a36Sopenharmony_ci return err; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* set stack pointer to the end of the stack page, so it can grow downwards */ 32862306a36Sopenharmony_ci sp = (unsigned long)stack + UM_KERN_PAGE_SIZE; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci flags = CLONE_FILES | SIGCHLD; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* clone into new userspace process */ 33362306a36Sopenharmony_ci pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack); 33462306a36Sopenharmony_ci if (pid < 0) { 33562306a36Sopenharmony_ci err = -errno; 33662306a36Sopenharmony_ci printk(UM_KERN_ERR "%s : clone failed, errno = %d\n", 33762306a36Sopenharmony_ci __func__, errno); 33862306a36Sopenharmony_ci return err; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci do { 34262306a36Sopenharmony_ci CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL)); 34362306a36Sopenharmony_ci if (n < 0) { 34462306a36Sopenharmony_ci err = -errno; 34562306a36Sopenharmony_ci printk(UM_KERN_ERR "%s : wait failed, errno = %d\n", 34662306a36Sopenharmony_ci __func__, errno); 34762306a36Sopenharmony_ci goto out_kill; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGALRM)); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) { 35262306a36Sopenharmony_ci err = -EINVAL; 35362306a36Sopenharmony_ci printk(UM_KERN_ERR "%s : expected SIGSTOP, got status = %d\n", 35462306a36Sopenharmony_ci __func__, status); 35562306a36Sopenharmony_ci goto out_kill; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, 35962306a36Sopenharmony_ci (void *) PTRACE_O_TRACESYSGOOD) < 0) { 36062306a36Sopenharmony_ci err = -errno; 36162306a36Sopenharmony_ci printk(UM_KERN_ERR "%s : PTRACE_OLDSETOPTIONS failed, errno = %d\n", 36262306a36Sopenharmony_ci __func__, errno); 36362306a36Sopenharmony_ci goto out_kill; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (munmap(stack, UM_KERN_PAGE_SIZE) < 0) { 36762306a36Sopenharmony_ci err = -errno; 36862306a36Sopenharmony_ci printk(UM_KERN_ERR "%s : munmap failed, errno = %d\n", 36962306a36Sopenharmony_ci __func__, errno); 37062306a36Sopenharmony_ci goto out_kill; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci return pid; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci out_kill: 37662306a36Sopenharmony_ci os_kill_ptraced_process(pid, 1); 37762306a36Sopenharmony_ci return err; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_civoid userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci int err, status, op, pid = userspace_pid[0]; 38362306a36Sopenharmony_ci /* To prevent races if using_sysemu changes under us.*/ 38462306a36Sopenharmony_ci int local_using_sysemu; 38562306a36Sopenharmony_ci siginfo_t si; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* Handle any immediate reschedules or signals */ 38862306a36Sopenharmony_ci interrupt_end(); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci while (1) { 39162306a36Sopenharmony_ci if (kill_userspace_mm[0]) 39262306a36Sopenharmony_ci fatal_sigsegv(); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* 39562306a36Sopenharmony_ci * This can legitimately fail if the process loads a 39662306a36Sopenharmony_ci * bogus value into a segment register. It will 39762306a36Sopenharmony_ci * segfault and PTRACE_GETREGS will read that value 39862306a36Sopenharmony_ci * out of the process. However, PTRACE_SETREGS will 39962306a36Sopenharmony_ci * fail. In this case, there is nothing to do but 40062306a36Sopenharmony_ci * just kill the process. 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_ci if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) { 40362306a36Sopenharmony_ci printk(UM_KERN_ERR "%s - ptrace set regs failed, errno = %d\n", 40462306a36Sopenharmony_ci __func__, errno); 40562306a36Sopenharmony_ci fatal_sigsegv(); 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (put_fp_registers(pid, regs->fp)) { 40962306a36Sopenharmony_ci printk(UM_KERN_ERR "%s - ptrace set fp regs failed, errno = %d\n", 41062306a36Sopenharmony_ci __func__, errno); 41162306a36Sopenharmony_ci fatal_sigsegv(); 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* Now we set local_using_sysemu to be used for one loop */ 41562306a36Sopenharmony_ci local_using_sysemu = get_using_sysemu(); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci op = SELECT_PTRACE_OPERATION(local_using_sysemu, 41862306a36Sopenharmony_ci singlestepping(NULL)); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (ptrace(op, pid, 0, 0)) { 42162306a36Sopenharmony_ci printk(UM_KERN_ERR "%s - ptrace continue failed, op = %d, errno = %d\n", 42262306a36Sopenharmony_ci __func__, op, errno); 42362306a36Sopenharmony_ci fatal_sigsegv(); 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL)); 42762306a36Sopenharmony_ci if (err < 0) { 42862306a36Sopenharmony_ci printk(UM_KERN_ERR "%s - wait failed, errno = %d\n", 42962306a36Sopenharmony_ci __func__, errno); 43062306a36Sopenharmony_ci fatal_sigsegv(); 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci regs->is_user = 1; 43462306a36Sopenharmony_ci if (ptrace(PTRACE_GETREGS, pid, 0, regs->gp)) { 43562306a36Sopenharmony_ci printk(UM_KERN_ERR "%s - PTRACE_GETREGS failed, errno = %d\n", 43662306a36Sopenharmony_ci __func__, errno); 43762306a36Sopenharmony_ci fatal_sigsegv(); 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (get_fp_registers(pid, regs->fp)) { 44162306a36Sopenharmony_ci printk(UM_KERN_ERR "%s - get_fp_registers failed, errno = %d\n", 44262306a36Sopenharmony_ci __func__, errno); 44362306a36Sopenharmony_ci fatal_sigsegv(); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (WIFSTOPPED(status)) { 44962306a36Sopenharmony_ci int sig = WSTOPSIG(status); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* These signal handlers need the si argument. 45262306a36Sopenharmony_ci * The SIGIO and SIGALARM handlers which constitute the 45362306a36Sopenharmony_ci * majority of invocations, do not use it. 45462306a36Sopenharmony_ci */ 45562306a36Sopenharmony_ci switch (sig) { 45662306a36Sopenharmony_ci case SIGSEGV: 45762306a36Sopenharmony_ci case SIGTRAP: 45862306a36Sopenharmony_ci case SIGILL: 45962306a36Sopenharmony_ci case SIGBUS: 46062306a36Sopenharmony_ci case SIGFPE: 46162306a36Sopenharmony_ci case SIGWINCH: 46262306a36Sopenharmony_ci ptrace(PTRACE_GETSIGINFO, pid, 0, (struct siginfo *)&si); 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci switch (sig) { 46762306a36Sopenharmony_ci case SIGSEGV: 46862306a36Sopenharmony_ci if (PTRACE_FULL_FAULTINFO) { 46962306a36Sopenharmony_ci get_skas_faultinfo(pid, 47062306a36Sopenharmony_ci ®s->faultinfo, aux_fp_regs); 47162306a36Sopenharmony_ci (*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si, 47262306a36Sopenharmony_ci regs); 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci else handle_segv(pid, regs, aux_fp_regs); 47562306a36Sopenharmony_ci break; 47662306a36Sopenharmony_ci case SIGTRAP + 0x80: 47762306a36Sopenharmony_ci handle_trap(pid, regs, local_using_sysemu); 47862306a36Sopenharmony_ci break; 47962306a36Sopenharmony_ci case SIGTRAP: 48062306a36Sopenharmony_ci relay_signal(SIGTRAP, (struct siginfo *)&si, regs); 48162306a36Sopenharmony_ci break; 48262306a36Sopenharmony_ci case SIGALRM: 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci case SIGIO: 48562306a36Sopenharmony_ci case SIGILL: 48662306a36Sopenharmony_ci case SIGBUS: 48762306a36Sopenharmony_ci case SIGFPE: 48862306a36Sopenharmony_ci case SIGWINCH: 48962306a36Sopenharmony_ci block_signals_trace(); 49062306a36Sopenharmony_ci (*sig_info[sig])(sig, (struct siginfo *)&si, regs); 49162306a36Sopenharmony_ci unblock_signals_trace(); 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci default: 49462306a36Sopenharmony_ci printk(UM_KERN_ERR "%s - child stopped with signal %d\n", 49562306a36Sopenharmony_ci __func__, sig); 49662306a36Sopenharmony_ci fatal_sigsegv(); 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci pid = userspace_pid[0]; 49962306a36Sopenharmony_ci interrupt_end(); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci /* Avoid -ERESTARTSYS handling in host */ 50262306a36Sopenharmony_ci if (PT_SYSCALL_NR_OFFSET != PT_SYSCALL_RET_OFFSET) 50362306a36Sopenharmony_ci PT_SYSCALL_NR(regs->gp) = -1; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic unsigned long thread_regs[MAX_REG_NR]; 50962306a36Sopenharmony_cistatic unsigned long thread_fp_regs[FP_SIZE]; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic int __init init_thread_regs(void) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci get_safe_registers(thread_regs, thread_fp_regs); 51462306a36Sopenharmony_ci /* Set parent's instruction pointer to start of clone-stub */ 51562306a36Sopenharmony_ci thread_regs[REGS_IP_INDEX] = STUB_CODE + 51662306a36Sopenharmony_ci (unsigned long) stub_clone_handler - 51762306a36Sopenharmony_ci (unsigned long) __syscall_stub_start; 51862306a36Sopenharmony_ci thread_regs[REGS_SP_INDEX] = STUB_DATA + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 51962306a36Sopenharmony_ci sizeof(void *); 52062306a36Sopenharmony_ci#ifdef __SIGNAL_FRAMESIZE 52162306a36Sopenharmony_ci thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE; 52262306a36Sopenharmony_ci#endif 52362306a36Sopenharmony_ci return 0; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci__initcall(init_thread_regs); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ciint copy_context_skas0(unsigned long new_stack, int pid) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci int err; 53162306a36Sopenharmony_ci unsigned long current_stack = current_stub_stack(); 53262306a36Sopenharmony_ci struct stub_data *data = (struct stub_data *) current_stack; 53362306a36Sopenharmony_ci struct stub_data *child_data = (struct stub_data *) new_stack; 53462306a36Sopenharmony_ci unsigned long long new_offset; 53562306a36Sopenharmony_ci int new_fd = phys_mapping(uml_to_phys((void *)new_stack), &new_offset); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* 53862306a36Sopenharmony_ci * prepare offset and fd of child's stack as argument for parent's 53962306a36Sopenharmony_ci * and child's mmap2 calls 54062306a36Sopenharmony_ci */ 54162306a36Sopenharmony_ci *data = ((struct stub_data) { 54262306a36Sopenharmony_ci .offset = MMAP_OFFSET(new_offset), 54362306a36Sopenharmony_ci .fd = new_fd, 54462306a36Sopenharmony_ci .parent_err = -ESRCH, 54562306a36Sopenharmony_ci .child_err = 0, 54662306a36Sopenharmony_ci }); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci *child_data = ((struct stub_data) { 54962306a36Sopenharmony_ci .child_err = -ESRCH, 55062306a36Sopenharmony_ci }); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci err = ptrace_setregs(pid, thread_regs); 55362306a36Sopenharmony_ci if (err < 0) { 55462306a36Sopenharmony_ci err = -errno; 55562306a36Sopenharmony_ci printk(UM_KERN_ERR "%s : PTRACE_SETREGS failed, pid = %d, errno = %d\n", 55662306a36Sopenharmony_ci __func__, pid, -err); 55762306a36Sopenharmony_ci return err; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci err = put_fp_registers(pid, thread_fp_regs); 56162306a36Sopenharmony_ci if (err < 0) { 56262306a36Sopenharmony_ci printk(UM_KERN_ERR "%s : put_fp_registers failed, pid = %d, err = %d\n", 56362306a36Sopenharmony_ci __func__, pid, err); 56462306a36Sopenharmony_ci return err; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* 56862306a36Sopenharmony_ci * Wait, until parent has finished its work: read child's pid from 56962306a36Sopenharmony_ci * parent's stack, and check, if bad result. 57062306a36Sopenharmony_ci */ 57162306a36Sopenharmony_ci err = ptrace(PTRACE_CONT, pid, 0, 0); 57262306a36Sopenharmony_ci if (err) { 57362306a36Sopenharmony_ci err = -errno; 57462306a36Sopenharmony_ci printk(UM_KERN_ERR "Failed to continue new process, pid = %d, errno = %d\n", 57562306a36Sopenharmony_ci pid, errno); 57662306a36Sopenharmony_ci return err; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci wait_stub_done(pid); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci pid = data->parent_err; 58262306a36Sopenharmony_ci if (pid < 0) { 58362306a36Sopenharmony_ci printk(UM_KERN_ERR "%s - stub-parent reports error %d\n", 58462306a36Sopenharmony_ci __func__, -pid); 58562306a36Sopenharmony_ci return pid; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* 58962306a36Sopenharmony_ci * Wait, until child has finished too: read child's result from 59062306a36Sopenharmony_ci * child's stack and check it. 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_ci wait_stub_done(pid); 59362306a36Sopenharmony_ci if (child_data->child_err != STUB_DATA) { 59462306a36Sopenharmony_ci printk(UM_KERN_ERR "%s - stub-child %d reports error %ld\n", 59562306a36Sopenharmony_ci __func__, pid, data->child_err); 59662306a36Sopenharmony_ci err = data->child_err; 59762306a36Sopenharmony_ci goto out_kill; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, 60162306a36Sopenharmony_ci (void *)PTRACE_O_TRACESYSGOOD) < 0) { 60262306a36Sopenharmony_ci err = -errno; 60362306a36Sopenharmony_ci printk(UM_KERN_ERR "%s : PTRACE_OLDSETOPTIONS failed, errno = %d\n", 60462306a36Sopenharmony_ci __func__, errno); 60562306a36Sopenharmony_ci goto out_kill; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci return pid; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci out_kill: 61162306a36Sopenharmony_ci os_kill_ptraced_process(pid, 1); 61262306a36Sopenharmony_ci return err; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_civoid new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci (*buf)[0].JB_IP = (unsigned long) handler; 61862306a36Sopenharmony_ci (*buf)[0].JB_SP = (unsigned long) stack + UM_THREAD_SIZE - 61962306a36Sopenharmony_ci sizeof(void *); 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci#define INIT_JMP_NEW_THREAD 0 62362306a36Sopenharmony_ci#define INIT_JMP_CALLBACK 1 62462306a36Sopenharmony_ci#define INIT_JMP_HALT 2 62562306a36Sopenharmony_ci#define INIT_JMP_REBOOT 3 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_civoid switch_threads(jmp_buf *me, jmp_buf *you) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci if (UML_SETJMP(me) == 0) 63062306a36Sopenharmony_ci UML_LONGJMP(you, 1); 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic jmp_buf initial_jmpbuf; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci/* XXX Make these percpu */ 63662306a36Sopenharmony_cistatic void (*cb_proc)(void *arg); 63762306a36Sopenharmony_cistatic void *cb_arg; 63862306a36Sopenharmony_cistatic jmp_buf *cb_back; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ciint start_idle_thread(void *stack, jmp_buf *switch_buf) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci int n; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci set_handler(SIGWINCH); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* 64762306a36Sopenharmony_ci * Can't use UML_SETJMP or UML_LONGJMP here because they save 64862306a36Sopenharmony_ci * and restore signals, with the possible side-effect of 64962306a36Sopenharmony_ci * trying to handle any signals which came when they were 65062306a36Sopenharmony_ci * blocked, which can't be done on this stack. 65162306a36Sopenharmony_ci * Signals must be blocked when jumping back here and restored 65262306a36Sopenharmony_ci * after returning to the jumper. 65362306a36Sopenharmony_ci */ 65462306a36Sopenharmony_ci n = setjmp(initial_jmpbuf); 65562306a36Sopenharmony_ci switch (n) { 65662306a36Sopenharmony_ci case INIT_JMP_NEW_THREAD: 65762306a36Sopenharmony_ci (*switch_buf)[0].JB_IP = (unsigned long) uml_finishsetup; 65862306a36Sopenharmony_ci (*switch_buf)[0].JB_SP = (unsigned long) stack + 65962306a36Sopenharmony_ci UM_THREAD_SIZE - sizeof(void *); 66062306a36Sopenharmony_ci break; 66162306a36Sopenharmony_ci case INIT_JMP_CALLBACK: 66262306a36Sopenharmony_ci (*cb_proc)(cb_arg); 66362306a36Sopenharmony_ci longjmp(*cb_back, 1); 66462306a36Sopenharmony_ci break; 66562306a36Sopenharmony_ci case INIT_JMP_HALT: 66662306a36Sopenharmony_ci kmalloc_ok = 0; 66762306a36Sopenharmony_ci return 0; 66862306a36Sopenharmony_ci case INIT_JMP_REBOOT: 66962306a36Sopenharmony_ci kmalloc_ok = 0; 67062306a36Sopenharmony_ci return 1; 67162306a36Sopenharmony_ci default: 67262306a36Sopenharmony_ci printk(UM_KERN_ERR "Bad sigsetjmp return in %s - %d\n", 67362306a36Sopenharmony_ci __func__, n); 67462306a36Sopenharmony_ci fatal_sigsegv(); 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci longjmp(*switch_buf, 1); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci /* unreachable */ 67962306a36Sopenharmony_ci printk(UM_KERN_ERR "impossible long jump!"); 68062306a36Sopenharmony_ci fatal_sigsegv(); 68162306a36Sopenharmony_ci return 0; 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_civoid initial_thread_cb_skas(void (*proc)(void *), void *arg) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci jmp_buf here; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci cb_proc = proc; 68962306a36Sopenharmony_ci cb_arg = arg; 69062306a36Sopenharmony_ci cb_back = &here; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci block_signals_trace(); 69362306a36Sopenharmony_ci if (UML_SETJMP(&here) == 0) 69462306a36Sopenharmony_ci UML_LONGJMP(&initial_jmpbuf, INIT_JMP_CALLBACK); 69562306a36Sopenharmony_ci unblock_signals_trace(); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci cb_proc = NULL; 69862306a36Sopenharmony_ci cb_arg = NULL; 69962306a36Sopenharmony_ci cb_back = NULL; 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_civoid halt_skas(void) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci block_signals_trace(); 70562306a36Sopenharmony_ci UML_LONGJMP(&initial_jmpbuf, INIT_JMP_HALT); 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic bool noreboot; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic int __init noreboot_cmd_param(char *str, int *add) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci noreboot = true; 71362306a36Sopenharmony_ci return 0; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci__uml_setup("noreboot", noreboot_cmd_param, 71762306a36Sopenharmony_ci"noreboot\n" 71862306a36Sopenharmony_ci" Rather than rebooting, exit always, akin to QEMU's -no-reboot option.\n" 71962306a36Sopenharmony_ci" This is useful if you're using CONFIG_PANIC_TIMEOUT in order to catch\n" 72062306a36Sopenharmony_ci" crashes in CI\n"); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_civoid reboot_skas(void) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci block_signals_trace(); 72562306a36Sopenharmony_ci UML_LONGJMP(&initial_jmpbuf, noreboot ? INIT_JMP_HALT : INIT_JMP_REBOOT); 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_civoid __switch_mm(struct mm_id *mm_idp) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci userspace_pid[0] = mm_idp->u.pid; 73162306a36Sopenharmony_ci kill_userspace_mm[0] = mm_idp->kill; 73262306a36Sopenharmony_ci} 733