Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

Pull UML updates from Richard Weinberger:

- Clang coverage support

- Many cleanups from Benjamin Berg

- Various minor fixes

* tag 'uml-for-linus-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/uml/linux:
um: Mark 32bit syscall helpers as clobbering memory
um: Remove unused register save/restore functions
um: Rely on PTRACE_SETREGSET to set FS/GS base registers
Documentation: kunit: Add clang UML coverage example
arch: um: Add Clang coverage support
um: time-travel: fix time corruption
um: net: Fix return type of uml_net_start_xmit()
um: Always inline stub functions
um: Do not use printk in userspace trampoline
um: Reap winch thread if it fails
um: Do not use printk in SIGWINCH helper thread
um: Don't use vfprintf() for os_info()
um: Make errors to stop ptraced child fatal during startup
um: Drop NULL check from start_userspace
um: Drop support for hosts without SYSEMU_SINGLESTEP support
um: document arch_futex_atomic_op_inuser
um: mmu: remove stub_pages
um: Fix naming clash between UML and scheduler
um: virt-pci: fix platform map offset

+220 -467
+11
Documentation/dev-tools/kunit/running_tips.rst
··· 139 139 $ ./tools/testing/kunit/kunit.py run --make_options=CC=/usr/bin/gcc-6 140 140 $ lcov -t "my_kunit_tests" -o coverage.info -c -d .kunit/ --gcov-tool=/usr/bin/gcov-6 141 141 142 + Alternatively, LLVM-based toolchains can also be used: 143 + 144 + .. code-block:: bash 145 + 146 + # Build with LLVM and append coverage options to the current config 147 + $ ./tools/testing/kunit/kunit.py run --make_options LLVM=1 --kunitconfig=.kunit/ --kunitconfig=tools/testing/kunit/configs/coverage_uml.config 148 + $ llvm-profdata merge -sparse default.profraw -o default.profdata 149 + $ llvm-cov export --format=lcov .kunit/vmlinux -instr-profile default.profdata > coverage.info 150 + # The coverage.info file is in lcov-compatible format and it can be used to e.g. generate HTML report 151 + $ genhtml -o /tmp/coverage_html coverage.info 152 + 142 153 143 154 Running tests manually 144 155 ======================
+5
arch/um/Makefile-skas
··· 4 4 # 5 5 6 6 GPROF_OPT += -pg 7 + 8 + ifdef CONFIG_CC_IS_CLANG 9 + GCOV_OPT += -fprofile-instr-generate -fcoverage-mapping 10 + else 7 11 GCOV_OPT += -fprofile-arcs -ftest-coverage 12 + endif 8 13 9 14 CFLAGS-$(CONFIG_GCOV) += $(GCOV_OPT) 10 15 CFLAGS-$(CONFIG_GPROF) += $(GPROF_OPT)
+24 -18
arch/um/drivers/chan_user.c
··· 141 141 int pipe_fd; 142 142 }; 143 143 144 - static int winch_thread(void *arg) 144 + static __noreturn int winch_thread(void *arg) 145 145 { 146 146 struct winch_data *data = arg; 147 147 sigset_t sigs; ··· 153 153 pipe_fd = data->pipe_fd; 154 154 count = write(pipe_fd, &c, sizeof(c)); 155 155 if (count != sizeof(c)) 156 - printk(UM_KERN_ERR "winch_thread : failed to write " 157 - "synchronization byte, err = %d\n", -count); 156 + os_info("winch_thread : failed to write synchronization byte, err = %d\n", 157 + -count); 158 158 159 159 /* 160 160 * We are not using SIG_IGN on purpose, so don't fix it as I thought to ··· 166 166 sigfillset(&sigs); 167 167 /* Block all signals possible. */ 168 168 if (sigprocmask(SIG_SETMASK, &sigs, NULL) < 0) { 169 - printk(UM_KERN_ERR "winch_thread : sigprocmask failed, " 170 - "errno = %d\n", errno); 171 - exit(1); 169 + os_info("winch_thread : sigprocmask failed, errno = %d\n", 170 + errno); 171 + goto wait_kill; 172 172 } 173 173 /* In sigsuspend(), block anything else than SIGWINCH. */ 174 174 sigdelset(&sigs, SIGWINCH); 175 175 176 176 if (setsid() < 0) { 177 - printk(UM_KERN_ERR "winch_thread : setsid failed, errno = %d\n", 177 + os_info("winch_thread : setsid failed, errno = %d\n", 178 178 errno); 179 - exit(1); 179 + goto wait_kill; 180 180 } 181 181 182 182 if (ioctl(pty_fd, TIOCSCTTY, 0) < 0) { 183 - printk(UM_KERN_ERR "winch_thread : TIOCSCTTY failed on " 184 - "fd %d err = %d\n", pty_fd, errno); 185 - exit(1); 183 + os_info("winch_thread : TIOCSCTTY failed on " 184 + "fd %d err = %d\n", pty_fd, errno); 185 + goto wait_kill; 186 186 } 187 187 188 188 if (tcsetpgrp(pty_fd, os_getpid()) < 0) { 189 - printk(UM_KERN_ERR "winch_thread : tcsetpgrp failed on " 190 - "fd %d err = %d\n", pty_fd, errno); 191 - exit(1); 189 + os_info("winch_thread : tcsetpgrp failed on fd %d err = %d\n", 190 + pty_fd, errno); 191 + goto wait_kill; 192 192 } 193 193 194 194 /* ··· 199 199 */ 200 200 count = read(pipe_fd, &c, sizeof(c)); 201 201 if (count != sizeof(c)) 202 - printk(UM_KERN_ERR "winch_thread : failed to read " 203 - "synchronization byte, err = %d\n", errno); 202 + os_info("winch_thread : failed to read synchronization byte, err = %d\n", 203 + errno); 204 204 205 205 while(1) { 206 206 /* ··· 211 211 212 212 count = write(pipe_fd, &c, sizeof(c)); 213 213 if (count != sizeof(c)) 214 - printk(UM_KERN_ERR "winch_thread : write failed, " 215 - "err = %d\n", errno); 214 + os_info("winch_thread : write failed, err = %d\n", 215 + errno); 216 216 } 217 + 218 + wait_kill: 219 + c = 2; 220 + count = write(pipe_fd, &c, sizeof(c)); 221 + while (1) 222 + pause(); 217 223 } 218 224 219 225 static int winch_tramp(int fd, struct tty_port *port, int *fd_out,
+8 -5
arch/um/drivers/line.c
··· 629 629 630 630 if (fd != -1) { 631 631 err = generic_read(fd, &c, NULL); 632 - if (err < 0) { 632 + /* A read of 2 means the winch thread failed and has warned */ 633 + if (err < 0 || (err == 1 && c == 2)) { 633 634 if (err != -EAGAIN) { 634 635 winch->fd = -1; 635 636 list_del(&winch->list); 636 637 os_close_file(fd); 637 - printk(KERN_ERR "winch_interrupt : " 638 - "read failed, errno = %d\n", -err); 639 - printk(KERN_ERR "fd %d is losing SIGWINCH " 640 - "support\n", winch->tty_fd); 638 + if (err < 0) { 639 + printk(KERN_ERR "winch_interrupt : read failed, errno = %d\n", 640 + -err); 641 + printk(KERN_ERR "fd %d is losing SIGWINCH support\n", 642 + winch->tty_fd); 643 + } 641 644 INIT_WORK(&winch->work, __free_winch); 642 645 schedule_work(&winch->work); 643 646 return IRQ_HANDLED;
+1 -1
arch/um/drivers/net_kern.c
··· 204 204 return 0; 205 205 } 206 206 207 - static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) 207 + static netdev_tx_t uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) 208 208 { 209 209 struct uml_net_private *lp = netdev_priv(dev); 210 210 unsigned long flags;
+1 -1
arch/um/drivers/virt-pci.c
··· 971 971 *ops = &um_pci_device_bar_ops; 972 972 *priv = &um_pci_platform_device->resptr[0]; 973 973 974 - return 0; 974 + return offset; 975 975 } 976 976 977 977 static const struct logic_iomem_region_ops um_pci_platform_ops = {
-1
arch/um/include/asm/mmu.h
··· 12 12 typedef struct mm_context { 13 13 struct mm_id id; 14 14 struct uml_arch_mm_context arch; 15 - struct page *stub_pages[2]; 16 15 } mm_context_t; 17 16 18 17 extern void __switch_mm(struct mm_id * mm_idp);
-1
arch/um/include/asm/processor-generic.h
··· 22 22 struct thread_struct { 23 23 struct pt_regs regs; 24 24 struct pt_regs *segv_regs; 25 - int singlestep_syscall; 26 25 void *fault_addr; 27 26 jmp_buf *fault_catcher; 28 27 struct task_struct *prev_sched;
+2 -3
arch/um/include/shared/kern_util.h
··· 34 34 35 35 extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs); 36 36 extern void initial_thread_cb(void (*proc)(void *), void *arg); 37 - extern int is_syscall(unsigned long addr); 38 37 39 38 extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); 40 39 ··· 49 50 * Are we disallowed to sleep? Used to choose between GFP_KERNEL and 50 51 * GFP_ATOMIC. 51 52 */ 52 - extern int __cant_sleep(void); 53 + extern int __uml_cant_sleep(void); 53 54 extern int get_current_pid(void); 54 55 extern int copy_from_user_proc(void *to, void *from, int size); 55 56 extern char *uml_strdup(const char *string); ··· 57 58 extern unsigned long to_irq_stack(unsigned long *mask_out); 58 59 extern unsigned long from_irq_stack(int nested); 59 60 60 - extern int singlestepping(void *t); 61 + extern int singlestepping(void); 61 62 62 63 extern void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); 63 64 extern void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs);
-3
arch/um/include/shared/os.h
··· 323 323 extern int __add_sigio_fd(int fd); 324 324 extern int __ignore_sigio_fd(int fd); 325 325 326 - /* prctl.c */ 327 - extern int os_arch_prctl(int pid, int option, unsigned long *arg2); 328 - 329 326 /* tty.c */ 330 327 extern int get_pty(void); 331 328
-41
arch/um/include/shared/ptrace_user.h
··· 12 12 extern int ptrace_getregs(long pid, unsigned long *regs_out); 13 13 extern int ptrace_setregs(long pid, unsigned long *regs_in); 14 14 15 - /* syscall emulation path in ptrace */ 16 - 17 - #ifndef PTRACE_SYSEMU 18 - #define PTRACE_SYSEMU 31 19 - #endif 20 - #ifndef PTRACE_SYSEMU_SINGLESTEP 21 - #define PTRACE_SYSEMU_SINGLESTEP 32 22 - #endif 23 - 24 - /* On architectures, that started to support PTRACE_O_TRACESYSGOOD 25 - * in linux 2.4, there are two different definitions of 26 - * PTRACE_SETOPTIONS: linux 2.4 uses 21 while linux 2.6 uses 0x4200. 27 - * For binary compatibility, 2.6 also supports the old "21", named 28 - * PTRACE_OLDSETOPTION. On these architectures, UML always must use 29 - * "21", to ensure the kernel runs on 2.4 and 2.6 host without 30 - * recompilation. So, we use PTRACE_OLDSETOPTIONS in UML. 31 - * We also want to be able to build the kernel on 2.4, which doesn't 32 - * have PTRACE_OLDSETOPTIONS. So, if it is missing, we declare 33 - * PTRACE_OLDSETOPTIONS to be the same as PTRACE_SETOPTIONS. 34 - * 35 - * On architectures, that start to support PTRACE_O_TRACESYSGOOD on 36 - * linux 2.6, PTRACE_OLDSETOPTIONS never is defined, and also isn't 37 - * supported by the host kernel. In that case, our trick lets us use 38 - * the new 0x4200 with the name PTRACE_OLDSETOPTIONS. 39 - */ 40 - #ifndef PTRACE_OLDSETOPTIONS 41 - #define PTRACE_OLDSETOPTIONS PTRACE_SETOPTIONS 42 - #endif 43 - 44 - void set_using_sysemu(int value); 45 - int get_using_sysemu(void); 46 - extern int sysemu_supported; 47 - 48 - #define SELECT_PTRACE_OPERATION(sysemu_mode, singlestep_mode) \ 49 - (((int[3][3] ) { \ 50 - { PTRACE_SYSCALL, PTRACE_SYSCALL, PTRACE_SINGLESTEP }, \ 51 - { PTRACE_SYSEMU, PTRACE_SYSEMU, PTRACE_SINGLESTEP }, \ 52 - { PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP, \ 53 - PTRACE_SYSEMU_SINGLESTEP } }) \ 54 - [sysemu_mode][singlestep_mode]) 55 - 56 15 #endif
-2
arch/um/include/shared/registers.h
··· 14 14 extern int restore_fp_registers(int pid, unsigned long *fp_regs); 15 15 extern int save_fpx_registers(int pid, unsigned long *fp_regs); 16 16 extern int restore_fpx_registers(int pid, unsigned long *fp_regs); 17 - extern int save_registers(int pid, struct uml_pt_regs *regs); 18 - extern int restore_pid_registers(int pid, struct uml_pt_regs *regs); 19 17 extern int init_pid_registers(int pid); 20 18 extern void get_safe_registers(unsigned long *regs, unsigned long *fp_regs); 21 19 extern int get_fp_registers(int pid, unsigned long *regs);
+3 -11
arch/um/kernel/process.c
··· 220 220 um_idle_sleep(); 221 221 } 222 222 223 - int __cant_sleep(void) { 223 + int __uml_cant_sleep(void) { 224 224 return in_atomic() || irqs_disabled() || in_interrupt(); 225 225 /* Is in_interrupt() really needed? */ 226 226 } ··· 332 332 333 333 late_initcall(make_proc_sysemu); 334 334 335 - int singlestepping(void * t) 335 + int singlestepping(void) 336 336 { 337 - struct task_struct *task = t ? t : current; 338 - 339 - if (!test_thread_flag(TIF_SINGLESTEP)) 340 - return 0; 341 - 342 - if (task->thread.singlestep_syscall) 343 - return 1; 344 - 345 - return 2; 337 + return test_thread_flag(TIF_SINGLESTEP); 346 338 } 347 339 348 340 /*
-2
arch/um/kernel/ptrace.c
··· 12 12 void user_enable_single_step(struct task_struct *child) 13 13 { 14 14 set_tsk_thread_flag(child, TIF_SINGLESTEP); 15 - child->thread.singlestep_syscall = 0; 16 15 17 16 #ifdef SUBARCH_SET_SINGLESTEPPING 18 17 SUBARCH_SET_SINGLESTEPPING(child, 1); ··· 21 22 void user_disable_single_step(struct task_struct *child) 22 23 { 23 24 clear_tsk_thread_flag(child, TIF_SINGLESTEP); 24 - child->thread.singlestep_syscall = 0; 25 25 26 26 #ifdef SUBARCH_SET_SINGLESTEPPING 27 27 SUBARCH_SET_SINGLESTEPPING(child, 0);
-12
arch/um/kernel/signal.c
··· 121 121 } 122 122 123 123 /* 124 - * This closes a way to execute a system call on the host. If 125 - * you set a breakpoint on a system call instruction and singlestep 126 - * from it, the tracing thread used to PTRACE_SINGLESTEP the process 127 - * rather than PTRACE_SYSCALL it, allowing the system call to execute 128 - * on the host. The tracing thread will check this flag and 129 - * PTRACE_SYSCALL if necessary. 130 - */ 131 - if (test_thread_flag(TIF_SINGLESTEP)) 132 - current->thread.singlestep_syscall = 133 - is_syscall(PT_REGS_IP(&current->thread.regs)); 134 - 135 - /* 136 124 * if there's no signal to deliver, we just put the saved sigmask 137 125 * back 138 126 */
+3 -1
arch/um/kernel/skas/uaccess.c
··· 236 236 * argument and comparison of the previous 237 237 * futex value with another constant. 238 238 * 239 - * @encoded_op: encoded operation to execute 239 + * @op: operation to execute 240 + * @oparg: argument to operation 241 + * @oval: old value at uaddr 240 242 * @uaddr: pointer to user space address 241 243 * 242 244 * Return:
+27 -5
arch/um/kernel/time.c
··· 432 432 time_travel_del_event(&ne); 433 433 } 434 434 435 + static void time_travel_update_time_rel(unsigned long long offs) 436 + { 437 + unsigned long flags; 438 + 439 + /* 440 + * Disable interrupts before calculating the new time so 441 + * that a real timer interrupt (signal) can't happen at 442 + * a bad time e.g. after we read time_travel_time but 443 + * before we've completed updating the time. 444 + */ 445 + local_irq_save(flags); 446 + time_travel_update_time(time_travel_time + offs, false); 447 + local_irq_restore(flags); 448 + } 449 + 435 450 void time_travel_ndelay(unsigned long nsec) 436 451 { 437 - time_travel_update_time(time_travel_time + nsec, false); 452 + /* 453 + * Not strictly needed to use _rel() version since this is 454 + * only used in INFCPU/EXT modes, but it doesn't hurt and 455 + * is more readable too. 456 + */ 457 + time_travel_update_time_rel(nsec); 438 458 } 439 459 EXPORT_SYMBOL(time_travel_ndelay); 440 460 ··· 588 568 #define time_travel_time 0 589 569 #define time_travel_ext_waiting 0 590 570 591 - static inline void time_travel_update_time(unsigned long long ns, bool retearly) 571 + static inline void time_travel_update_time(unsigned long long ns, bool idle) 572 + { 573 + } 574 + 575 + static inline void time_travel_update_time_rel(unsigned long long offs) 592 576 { 593 577 } 594 578 ··· 744 720 */ 745 721 if (!irqs_disabled() && !in_interrupt() && !in_softirq() && 746 722 !time_travel_ext_waiting) 747 - time_travel_update_time(time_travel_time + 748 - TIMER_MULTIPLIER, 749 - false); 723 + time_travel_update_time_rel(TIMER_MULTIPLIER); 750 724 return time_travel_time / TIMER_MULTIPLIER; 751 725 } 752 726
+3 -3
arch/um/os-Linux/helper.c
··· 46 46 unsigned long stack, sp; 47 47 int pid, fds[2], ret, n; 48 48 49 - stack = alloc_stack(0, __cant_sleep()); 49 + stack = alloc_stack(0, __uml_cant_sleep()); 50 50 if (stack == 0) 51 51 return -ENOMEM; 52 52 ··· 70 70 data.pre_data = pre_data; 71 71 data.argv = argv; 72 72 data.fd = fds[1]; 73 - data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) : 73 + data.buf = __uml_cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) : 74 74 uml_kmalloc(PATH_MAX, UM_GFP_KERNEL); 75 75 pid = clone(helper_child, (void *) sp, CLONE_VM, &data); 76 76 if (pid < 0) { ··· 121 121 unsigned long stack, sp; 122 122 int pid, status, err; 123 123 124 - stack = alloc_stack(0, __cant_sleep()); 124 + stack = alloc_stack(0, __uml_cant_sleep()); 125 125 if (stack == 0) 126 126 return -ENOMEM; 127 127
-20
arch/um/os-Linux/registers.c
··· 11 11 #include <sysdep/ptrace_user.h> 12 12 #include <registers.h> 13 13 14 - int save_registers(int pid, struct uml_pt_regs *regs) 15 - { 16 - int err; 17 - 18 - err = ptrace(PTRACE_GETREGS, pid, 0, regs->gp); 19 - if (err < 0) 20 - return -errno; 21 - return 0; 22 - } 23 - 24 - int restore_pid_registers(int pid, struct uml_pt_regs *regs) 25 - { 26 - int err; 27 - 28 - err = ptrace(PTRACE_SETREGS, pid, 0, regs->gp); 29 - if (err < 0) 30 - return -errno; 31 - return 0; 32 - } 33 - 34 14 /* This is set once at boot time and not changed thereafter */ 35 15 36 16 static unsigned long exec_regs[MAX_REG_NR];
+35 -80
arch/um/os-Linux/skas/process.c
··· 177 177 segv(regs->faultinfo, 0, 1, NULL); 178 178 } 179 179 180 - /* 181 - * To use the same value of using_sysemu as the caller, ask it that value 182 - * (in local_using_sysemu 183 - */ 184 - static void handle_trap(int pid, struct uml_pt_regs *regs, 185 - int local_using_sysemu) 180 + static void handle_trap(int pid, struct uml_pt_regs *regs) 186 181 { 187 - int err, status; 188 - 189 182 if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END)) 190 183 fatal_sigsegv(); 191 - 192 - if (!local_using_sysemu) 193 - { 194 - err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, 195 - __NR_getpid); 196 - if (err < 0) { 197 - printk(UM_KERN_ERR "%s - nullifying syscall failed, errno = %d\n", 198 - __func__, errno); 199 - fatal_sigsegv(); 200 - } 201 - 202 - err = ptrace(PTRACE_SYSCALL, pid, 0, 0); 203 - if (err < 0) { 204 - printk(UM_KERN_ERR "%s - continuing to end of syscall failed, errno = %d\n", 205 - __func__, errno); 206 - fatal_sigsegv(); 207 - } 208 - 209 - CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL)); 210 - if ((err < 0) || !WIFSTOPPED(status) || 211 - (WSTOPSIG(status) != SIGTRAP + 0x80)) { 212 - err = ptrace_dump_regs(pid); 213 - if (err) 214 - printk(UM_KERN_ERR "Failed to get registers from process, errno = %d\n", 215 - -err); 216 - printk(UM_KERN_ERR "%s - failed to wait at end of syscall, errno = %d, status = %d\n", 217 - __func__, errno, status); 218 - fatal_sigsegv(); 219 - } 220 - } 221 184 222 185 handle_syscall(regs); 223 186 } ··· 189 226 190 227 /** 191 228 * userspace_tramp() - userspace trampoline 192 - * @stack: pointer to the new userspace stack page, can be NULL, if? FIXME: 229 + * @stack: pointer to the new userspace stack page 193 230 * 194 231 * The userspace trampoline is used to setup a new userspace process in start_userspace() after it was clone()'ed. 195 232 * This function will run on a temporary stack page. ··· 204 241 */ 205 242 static int userspace_tramp(void *stack) 206 243 { 244 + struct sigaction sa; 207 245 void *addr; 208 246 int fd; 209 247 unsigned long long offset; 248 + unsigned long segv_handler = STUB_CODE + 249 + (unsigned long) stub_segv_handler - 250 + (unsigned long) __syscall_stub_start; 210 251 211 252 ptrace(PTRACE_TRACEME, 0, 0, 0); 212 253 ··· 221 254 addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE, 222 255 PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); 223 256 if (addr == MAP_FAILED) { 224 - printk(UM_KERN_ERR "mapping mmap stub at 0x%lx failed, errno = %d\n", 225 - STUB_CODE, errno); 257 + os_info("mapping mmap stub at 0x%lx failed, errno = %d\n", 258 + STUB_CODE, errno); 226 259 exit(1); 227 260 } 228 261 229 - if (stack != NULL) { 230 - fd = phys_mapping(uml_to_phys(stack), &offset); 231 - addr = mmap((void *) STUB_DATA, 232 - STUB_DATA_PAGES * UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, 233 - MAP_FIXED | MAP_SHARED, fd, offset); 234 - if (addr == MAP_FAILED) { 235 - printk(UM_KERN_ERR "mapping segfault stack at 0x%lx failed, errno = %d\n", 236 - STUB_DATA, errno); 237 - exit(1); 238 - } 262 + fd = phys_mapping(uml_to_phys(stack), &offset); 263 + addr = mmap((void *) STUB_DATA, 264 + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, 265 + MAP_FIXED | MAP_SHARED, fd, offset); 266 + if (addr == MAP_FAILED) { 267 + os_info("mapping segfault stack at 0x%lx failed, errno = %d\n", 268 + STUB_DATA, errno); 269 + exit(1); 239 270 } 240 - if (stack != NULL) { 241 - struct sigaction sa; 242 271 243 - unsigned long v = STUB_CODE + 244 - (unsigned long) stub_segv_handler - 245 - (unsigned long) __syscall_stub_start; 246 - 247 - set_sigstack((void *) STUB_DATA, STUB_DATA_PAGES * UM_KERN_PAGE_SIZE); 248 - sigemptyset(&sa.sa_mask); 249 - sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO; 250 - sa.sa_sigaction = (void *) v; 251 - sa.sa_restorer = NULL; 252 - if (sigaction(SIGSEGV, &sa, NULL) < 0) { 253 - printk(UM_KERN_ERR "%s - setting SIGSEGV handler failed - errno = %d\n", 254 - __func__, errno); 255 - exit(1); 256 - } 272 + set_sigstack((void *) STUB_DATA, STUB_DATA_PAGES * UM_KERN_PAGE_SIZE); 273 + sigemptyset(&sa.sa_mask); 274 + sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO; 275 + sa.sa_sigaction = (void *) segv_handler; 276 + sa.sa_restorer = NULL; 277 + if (sigaction(SIGSEGV, &sa, NULL) < 0) { 278 + os_info("%s - setting SIGSEGV handler failed - errno = %d\n", 279 + __func__, errno); 280 + exit(1); 257 281 } 258 282 259 283 kill(os_getpid(), SIGSTOP); ··· 256 298 257 299 /** 258 300 * start_userspace() - prepare a new userspace process 259 - * @stub_stack: pointer to the stub stack. Can be NULL, if? FIXME: 301 + * @stub_stack: pointer to the stub stack. 260 302 * 261 303 * Setups a new temporary stack page that is used while userspace_tramp() runs 262 304 * Clones the kernel process into a new userspace process, with FDs only. ··· 313 355 goto out_kill; 314 356 } 315 357 316 - if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, 358 + if (ptrace(PTRACE_SETOPTIONS, pid, NULL, 317 359 (void *) PTRACE_O_TRACESYSGOOD) < 0) { 318 360 err = -errno; 319 - printk(UM_KERN_ERR "%s : PTRACE_OLDSETOPTIONS failed, errno = %d\n", 361 + printk(UM_KERN_ERR "%s : PTRACE_SETOPTIONS failed, errno = %d\n", 320 362 __func__, errno); 321 363 goto out_kill; 322 364 } ··· 338 380 void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs) 339 381 { 340 382 int err, status, op, pid = userspace_pid[0]; 341 - /* To prevent races if using_sysemu changes under us.*/ 342 - int local_using_sysemu; 343 383 siginfo_t si; 344 384 345 385 /* Handle any immediate reschedules or signals */ ··· 367 411 fatal_sigsegv(); 368 412 } 369 413 370 - /* Now we set local_using_sysemu to be used for one loop */ 371 - local_using_sysemu = get_using_sysemu(); 372 - 373 - op = SELECT_PTRACE_OPERATION(local_using_sysemu, 374 - singlestepping(NULL)); 414 + if (singlestepping()) 415 + op = PTRACE_SYSEMU_SINGLESTEP; 416 + else 417 + op = PTRACE_SYSEMU; 375 418 376 419 if (ptrace(op, pid, 0, 0)) { 377 420 printk(UM_KERN_ERR "%s - ptrace continue failed, op = %d, errno = %d\n", ··· 429 474 else handle_segv(pid, regs, aux_fp_regs); 430 475 break; 431 476 case SIGTRAP + 0x80: 432 - handle_trap(pid, regs, local_using_sysemu); 477 + handle_trap(pid, regs); 433 478 break; 434 479 case SIGTRAP: 435 480 relay_signal(SIGTRAP, (struct siginfo *)&si, regs); ··· 552 597 goto out_kill; 553 598 } 554 599 555 - if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, 600 + if (ptrace(PTRACE_SETOPTIONS, pid, NULL, 556 601 (void *)PTRACE_O_TRACESYSGOOD) < 0) { 557 602 err = -errno; 558 - printk(UM_KERN_ERR "%s : PTRACE_OLDSETOPTIONS failed, errno = %d\n", 603 + printk(UM_KERN_ERR "%s : PTRACE_SETOPTIONS failed, errno = %d\n", 559 604 __func__, errno); 560 605 goto out_kill; 561 606 }
+18 -93
arch/um/os-Linux/start_up.c
··· 112 112 return pid; 113 113 } 114 114 115 - /* When testing for SYSEMU support, if it is one of the broken versions, we 116 - * must just avoid using sysemu, not panic, but only if SYSEMU features are 117 - * broken. 118 - * So only for SYSEMU features we test mustpanic, while normal host features 119 - * must work anyway! 120 - */ 121 - static int stop_ptraced_child(int pid, int exitcode, int mustexit) 115 + static void stop_ptraced_child(int pid, int exitcode) 122 116 { 123 - int status, n, ret = 0; 117 + int status, n; 124 118 125 - if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) { 126 - perror("stop_ptraced_child : ptrace failed"); 127 - return -1; 128 - } 119 + if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) 120 + fatal_perror("stop_ptraced_child : ptrace failed"); 121 + 129 122 CATCH_EINTR(n = waitpid(pid, &status, 0)); 130 123 if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { 131 124 int exit_with = WEXITSTATUS(status); 132 - if (exit_with == 2) 133 - non_fatal("check_ptrace : child exited with status 2. " 134 - "\nDisabling SYSEMU support.\n"); 135 - non_fatal("check_ptrace : child exited with exitcode %d, while " 136 - "expecting %d; status 0x%x\n", exit_with, 137 - exitcode, status); 138 - if (mustexit) 139 - exit(1); 140 - ret = -1; 125 + fatal("stop_ptraced_child : child exited with exitcode %d, " 126 + "while expecting %d; status 0x%x\n", exit_with, 127 + exitcode, status); 141 128 } 142 - 143 - return ret; 144 129 } 145 - 146 - /* Changed only during early boot */ 147 - static int force_sysemu_disabled = 0; 148 - 149 - static int __init nosysemu_cmd_param(char *str, int* add) 150 - { 151 - force_sysemu_disabled = 1; 152 - return 0; 153 - } 154 - 155 - __uml_setup("nosysemu", nosysemu_cmd_param, 156 - "nosysemu\n" 157 - " Turns off syscall emulation patch for ptrace (SYSEMU).\n" 158 - " SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n" 159 - " behaviour of ptrace() and helps reduce host context switch rates.\n" 160 - " To make it work, you need a kernel patch for your host, too.\n" 161 - " See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n" 162 - " information.\n\n"); 163 130 164 131 static void __init check_sysemu(void) 165 132 { 166 - unsigned long regs[MAX_REG_NR]; 167 133 int pid, n, status, count=0; 168 134 169 - os_info("Checking syscall emulation patch for ptrace..."); 170 - sysemu_supported = 0; 135 + os_info("Checking syscall emulation for ptrace..."); 171 136 pid = start_ptraced_child(); 172 137 173 - if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0) 174 - goto fail; 175 - 176 - CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); 177 - if (n < 0) 178 - fatal_perror("check_sysemu : wait failed"); 179 - if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) 180 - fatal("check_sysemu : expected SIGTRAP, got status = %d\n", 181 - status); 182 - 183 - if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) 184 - fatal_perror("check_sysemu : PTRACE_GETREGS failed"); 185 - if (PT_SYSCALL_NR(regs) != __NR_getpid) { 186 - non_fatal("check_sysemu got system call number %d, " 187 - "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid); 188 - goto fail; 189 - } 190 - 191 - n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); 192 - if (n < 0) { 193 - non_fatal("check_sysemu : failed to modify system call " 194 - "return"); 195 - goto fail; 196 - } 197 - 198 - if (stop_ptraced_child(pid, 0, 0) < 0) 199 - goto fail_stopped; 200 - 201 - sysemu_supported = 1; 202 - os_info("OK\n"); 203 - set_using_sysemu(!force_sysemu_disabled); 204 - 205 - os_info("Checking advanced syscall emulation patch for ptrace..."); 206 - pid = start_ptraced_child(); 207 - 208 - if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, 138 + if ((ptrace(PTRACE_SETOPTIONS, pid, 0, 209 139 (void *) PTRACE_O_TRACESYSGOOD) < 0)) 210 - fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed"); 140 + fatal_perror("check_sysemu: PTRACE_SETOPTIONS failed"); 211 141 212 142 while (1) { 213 143 count++; ··· 170 240 goto fail; 171 241 } 172 242 } 173 - if (stop_ptraced_child(pid, 0, 0) < 0) 174 - goto fail_stopped; 243 + stop_ptraced_child(pid, 0); 175 244 176 - sysemu_supported = 2; 177 245 os_info("OK\n"); 178 246 179 - if (!force_sysemu_disabled) 180 - set_using_sysemu(sysemu_supported); 181 247 return; 182 248 183 249 fail: 184 - stop_ptraced_child(pid, 1, 0); 185 - fail_stopped: 186 - non_fatal("missing\n"); 250 + stop_ptraced_child(pid, 1); 251 + fatal("missing\n"); 187 252 } 188 253 189 254 static void __init check_ptrace(void) ··· 188 263 os_info("Checking that ptrace can change system call numbers..."); 189 264 pid = start_ptraced_child(); 190 265 191 - if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, 266 + if ((ptrace(PTRACE_SETOPTIONS, pid, 0, 192 267 (void *) PTRACE_O_TRACESYSGOOD) < 0)) 193 - fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); 268 + fatal_perror("check_ptrace: PTRACE_SETOPTIONS failed"); 194 269 195 270 while (1) { 196 271 if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ··· 216 291 break; 217 292 } 218 293 } 219 - stop_ptraced_child(pid, 0, 1); 294 + stop_ptraced_child(pid, 0); 220 295 os_info("OK\n"); 221 296 check_sysemu(); 222 297 } ··· 295 370 pid = start_ptraced_child(); 296 371 if (init_pid_registers(pid)) 297 372 fatal("Failed to initialize default registers"); 298 - stop_ptraced_child(pid, 1, 1); 373 + stop_ptraced_child(pid, 1); 299 374 } 300 375 301 376 int __init parse_iomem(char *str, int *add)
+17 -2
arch/um/os-Linux/util.c
··· 173 173 "quiet\n" 174 174 " Turns off information messages during boot.\n\n"); 175 175 176 + /* 177 + * The os_info/os_warn functions will be called by helper threads. These 178 + * have a very limited stack size and using the libc formatting functions 179 + * may overflow the stack. 180 + * So pull in the kernel vscnprintf and use that instead with a fixed 181 + * on-stack buffer. 182 + */ 183 + int vscnprintf(char *buf, size_t size, const char *fmt, va_list args); 184 + 176 185 void os_info(const char *fmt, ...) 177 186 { 187 + char buf[256]; 178 188 va_list list; 189 + int len; 179 190 180 191 if (quiet_info) 181 192 return; 182 193 183 194 va_start(list, fmt); 184 - vfprintf(stderr, fmt, list); 195 + len = vscnprintf(buf, sizeof(buf), fmt, list); 196 + fwrite(buf, len, 1, stderr); 185 197 va_end(list); 186 198 } 187 199 188 200 void os_warn(const char *fmt, ...) 189 201 { 202 + char buf[256]; 190 203 va_list list; 204 + int len; 191 205 192 206 va_start(list, fmt); 193 - vfprintf(stderr, fmt, list); 207 + len = vscnprintf(buf, sizeof(buf), fmt, list); 208 + fwrite(buf, len, 1, stderr); 194 209 va_end(list); 195 210 }
+2 -2
arch/x86/um/asm/elf.h
··· 168 168 (pr_reg)[18] = (_regs)->regs.gp[18]; \ 169 169 (pr_reg)[19] = (_regs)->regs.gp[19]; \ 170 170 (pr_reg)[20] = (_regs)->regs.gp[20]; \ 171 - (pr_reg)[21] = current->thread.arch.fs; \ 172 - (pr_reg)[22] = 0; \ 171 + (pr_reg)[21] = (_regs)->regs.gp[21]; \ 172 + (pr_reg)[22] = (_regs)->regs.gp[22]; \ 173 173 (pr_reg)[23] = 0; \ 174 174 (pr_reg)[24] = 0; \ 175 175 (pr_reg)[25] = 0; \
-3
arch/x86/um/asm/processor_64.h
··· 10 10 struct arch_thread { 11 11 unsigned long debugregs[8]; 12 12 int debugregs_seq; 13 - unsigned long fs; 14 13 struct faultinfo faultinfo; 15 14 }; 16 15 17 16 #define INIT_ARCH_THREAD { .debugregs = { [ 0 ... 7 ] = 0 }, \ 18 17 .debugregs_seq = 0, \ 19 - .fs = 0, \ 20 18 .faultinfo = { 0, 0, 0 } } 21 19 22 20 #define STACKSLOTS_PER_LINE 4 ··· 26 28 static inline void arch_copy_thread(struct arch_thread *from, 27 29 struct arch_thread *to) 28 30 { 29 - to->fs = from->fs; 30 31 } 31 32 32 33 #define current_sp() ({ void *sp; __asm__("movq %%rsp, %0" : "=r" (sp) : ); sp; })
-1
arch/x86/um/os-Linux/Makefile
··· 6 6 obj-y = registers.o task_size.o mcontext.o 7 7 8 8 obj-$(CONFIG_X86_32) += tls.o 9 - obj-$(CONFIG_64BIT) += prctl.o 10 9 11 10 USER_OBJS := $(obj-y) 12 11
-12
arch/x86/um/os-Linux/prctl.c
··· 1 - /* 2 - * Copyright (C) 2007 Jeff Dike (jdike@{addtoit.com,linux.intel.com}) 3 - * Licensed under the GPL 4 - */ 5 - 6 - #include <sys/ptrace.h> 7 - #include <asm/ptrace.h> 8 - 9 - int os_arch_prctl(int pid, int option, unsigned long *arg2) 10 - { 11 - return ptrace(PTRACE_ARCH_PRCTL, pid, (unsigned long) arg2, option); 12 - }
-24
arch/x86/um/ptrace_32.c
··· 25 25 printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n"); 26 26 } 27 27 28 - int is_syscall(unsigned long addr) 29 - { 30 - unsigned short instr; 31 - int n; 32 - 33 - n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); 34 - if (n) { 35 - /* access_process_vm() grants access to vsyscall and stub, 36 - * while copy_from_user doesn't. Maybe access_process_vm is 37 - * slow, but that doesn't matter, since it will be called only 38 - * in case of singlestepping, if copy_from_user failed. 39 - */ 40 - n = access_process_vm(current, addr, &instr, sizeof(instr), 41 - FOLL_FORCE); 42 - if (n != sizeof(instr)) { 43 - printk(KERN_ERR "is_syscall : failed to read " 44 - "instruction from 0x%lx\n", addr); 45 - return 1; 46 - } 47 - } 48 - /* int 0x80 or sysenter */ 49 - return (instr == 0x80cd) || (instr == 0x340f); 50 - } 51 - 52 28 /* determines which flags the user has access to. */ 53 29 /* 1 = access 0 = no access */ 54 30 #define FLAG_MASK 0x00044dd5
-26
arch/x86/um/ptrace_64.c
··· 188 188 return put_user(tmp, (unsigned long *) data); 189 189 } 190 190 191 - /* XXX Mostly copied from sys-i386 */ 192 - int is_syscall(unsigned long addr) 193 - { 194 - unsigned short instr; 195 - int n; 196 - 197 - n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); 198 - if (n) { 199 - /* 200 - * access_process_vm() grants access to vsyscall and stub, 201 - * while copy_from_user doesn't. Maybe access_process_vm is 202 - * slow, but that doesn't matter, since it will be called only 203 - * in case of singlestepping, if copy_from_user failed. 204 - */ 205 - n = access_process_vm(current, addr, &instr, sizeof(instr), 206 - FOLL_FORCE); 207 - if (n != sizeof(instr)) { 208 - printk("is_syscall : failed to read instruction from " 209 - "0x%lx\n", addr); 210 - return 1; 211 - } 212 - } 213 - /* sysenter */ 214 - return instr == 0x050f; 215 - } 216 - 217 191 static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) 218 192 { 219 193 int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
-4
arch/x86/um/shared/sysdep/ptrace_32.h
··· 8 8 9 9 #define MAX_FP_NR HOST_FPX_SIZE 10 10 11 - void set_using_sysemu(int value); 12 - int get_using_sysemu(void); 13 - extern int sysemu_supported; 14 - 15 11 #define UPT_SYSCALL_ARG1(r) UPT_BX(r) 16 12 #define UPT_SYSCALL_ARG2(r) UPT_CX(r) 17 13 #define UPT_SYSCALL_ARG3(r) UPT_DX(r)
+6 -8
arch/x86/um/shared/sysdep/ptrace_user.h
··· 15 15 #define FP_SIZE ((HOST_FPX_SIZE > HOST_FP_SIZE) ? HOST_FPX_SIZE : HOST_FP_SIZE) 16 16 #else 17 17 #define FP_SIZE HOST_FP_SIZE 18 - 19 - /* 20 - * x86_64 FC3 doesn't define this in /usr/include/linux/ptrace.h even though 21 - * it's defined in the kernel's include/linux/ptrace.h. Additionally, use the 22 - * 2.4 name and value for 2.4 host compatibility. 23 - */ 24 - #ifndef PTRACE_OLDSETOPTIONS 25 - #define PTRACE_OLDSETOPTIONS 21 26 18 #endif 27 19 20 + /* 21 + * glibc before 2.27 does not include PTRACE_SYSEMU_SINGLESTEP in its enum, 22 + * ensure we have a definition by (re-)defining it here. 23 + */ 24 + #ifndef PTRACE_SYSEMU_SINGLESTEP 25 + #define PTRACE_SYSEMU_SINGLESTEP 32 28 26 #endif
+31 -24
arch/x86/um/shared/sysdep/stub_32.h
··· 12 12 #define STUB_MMAP_NR __NR_mmap2 13 13 #define MMAP_OFFSET(o) ((o) >> UM_KERN_PAGE_SHIFT) 14 14 15 - static inline long stub_syscall0(long syscall) 15 + static __always_inline long stub_syscall0(long syscall) 16 16 { 17 17 long ret; 18 18 19 - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall)); 19 + __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall) 20 + : "memory"); 20 21 21 22 return ret; 22 23 } 23 24 24 - static inline long stub_syscall1(long syscall, long arg1) 25 + static __always_inline long stub_syscall1(long syscall, long arg1) 25 26 { 26 27 long ret; 27 28 28 - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1)); 29 + __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1) 30 + : "memory"); 29 31 30 32 return ret; 31 33 } 32 34 33 - static inline long stub_syscall2(long syscall, long arg1, long arg2) 34 - { 35 - long ret; 36 - 37 - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), 38 - "c" (arg2)); 39 - 40 - return ret; 41 - } 42 - 43 - static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) 35 + static __always_inline long stub_syscall2(long syscall, long arg1, long arg2) 44 36 { 45 37 long ret; 46 38 47 39 __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), 48 - "c" (arg2), "d" (arg3)); 40 + "c" (arg2) 41 + : "memory"); 49 42 50 43 return ret; 51 44 } 52 45 53 - static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, 54 - long arg4) 46 + static __always_inline long stub_syscall3(long syscall, long arg1, long arg2, 47 + long arg3) 55 48 { 56 49 long ret; 57 50 58 51 __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), 59 - "c" (arg2), "d" (arg3), "S" (arg4)); 52 + "c" (arg2), "d" (arg3) 53 + : "memory"); 60 54 61 55 return ret; 62 56 } 63 57 64 - static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3, 65 - long arg4, long arg5) 58 + static __always_inline long stub_syscall4(long syscall, long arg1, long arg2, 59 + long arg3, long arg4) 66 60 { 67 61 long ret; 68 62 69 63 __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), 70 - "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5)); 64 + "c" (arg2), "d" (arg3), "S" (arg4) 65 + : "memory"); 71 66 72 67 return ret; 73 68 } 74 69 75 - static inline void trap_myself(void) 70 + static __always_inline long stub_syscall5(long syscall, long arg1, long arg2, 71 + long arg3, long arg4, long arg5) 72 + { 73 + long ret; 74 + 75 + __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), 76 + "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5) 77 + : "memory"); 78 + 79 + return ret; 80 + } 81 + 82 + static __always_inline void trap_myself(void) 76 83 { 77 84 __asm("int3"); 78 85 } 79 86 80 - static inline void remap_stack_and_trap(void) 87 + static __always_inline void remap_stack_and_trap(void) 81 88 { 82 89 __asm__ volatile ( 83 90 "movl %%esp,%%ebx ;"
+9 -8
arch/x86/um/shared/sysdep/stub_64.h
··· 16 16 #define __syscall_clobber "r11","rcx","memory" 17 17 #define __syscall "syscall" 18 18 19 - static inline long stub_syscall0(long syscall) 19 + static __always_inline long stub_syscall0(long syscall) 20 20 { 21 21 long ret; 22 22 ··· 27 27 return ret; 28 28 } 29 29 30 - static inline long stub_syscall2(long syscall, long arg1, long arg2) 30 + static __always_inline long stub_syscall2(long syscall, long arg1, long arg2) 31 31 { 32 32 long ret; 33 33 ··· 38 38 return ret; 39 39 } 40 40 41 - static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) 41 + static __always_inline long stub_syscall3(long syscall, long arg1, long arg2, 42 + long arg3) 42 43 { 43 44 long ret; 44 45 ··· 51 50 return ret; 52 51 } 53 52 54 - static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, 53 + static __always_inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, 55 54 long arg4) 56 55 { 57 56 long ret; ··· 65 64 return ret; 66 65 } 67 66 68 - static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3, 69 - long arg4, long arg5) 67 + static __always_inline long stub_syscall5(long syscall, long arg1, long arg2, 68 + long arg3, long arg4, long arg5) 70 69 { 71 70 long ret; 72 71 ··· 79 78 return ret; 80 79 } 81 80 82 - static inline void trap_myself(void) 81 + static __always_inline void trap_myself(void) 83 82 { 84 83 __asm("int3"); 85 84 } 86 85 87 - static inline void remap_stack_and_trap(void) 86 + static __always_inline void remap_stack_and_trap(void) 88 87 { 89 88 __asm__ volatile ( 90 89 "movq %0,%%rax ;"
+13 -49
arch/x86/um/syscalls_64.c
··· 16 16 long arch_prctl(struct task_struct *task, int option, 17 17 unsigned long __user *arg2) 18 18 { 19 - unsigned long *ptr = arg2, tmp; 20 - long ret; 21 - int pid = task->mm->context.id.u.pid; 22 - 23 - /* 24 - * With ARCH_SET_FS (and ARCH_SET_GS is treated similarly to 25 - * be safe), we need to call arch_prctl on the host because 26 - * setting %fs may result in something else happening (like a 27 - * GDT or thread.fs being set instead). So, we let the host 28 - * fiddle the registers and thread struct and restore the 29 - * registers afterwards. 30 - * 31 - * So, the saved registers are stored to the process (this 32 - * needed because a stub may have been the last thing to run), 33 - * arch_prctl is run on the host, then the registers are read 34 - * back. 35 - */ 36 - switch (option) { 37 - case ARCH_SET_FS: 38 - case ARCH_SET_GS: 39 - ret = restore_pid_registers(pid, &current->thread.regs.regs); 40 - if (ret) 41 - return ret; 42 - break; 43 - case ARCH_GET_FS: 44 - case ARCH_GET_GS: 45 - /* 46 - * With these two, we read to a local pointer and 47 - * put_user it to the userspace pointer that we were 48 - * given. If addr isn't valid (because it hasn't been 49 - * faulted in or is just bogus), we want put_user to 50 - * fault it in (or return -EFAULT) instead of having 51 - * the host return -EFAULT. 52 - */ 53 - ptr = &tmp; 54 - } 55 - 56 - ret = os_arch_prctl(pid, option, ptr); 57 - if (ret) 58 - return ret; 19 + long ret = -EINVAL; 59 20 60 21 switch (option) { 61 22 case ARCH_SET_FS: 62 - current->thread.arch.fs = (unsigned long) ptr; 63 - ret = save_registers(pid, &current->thread.regs.regs); 23 + current->thread.regs.regs.gp[FS_BASE / sizeof(unsigned long)] = 24 + (unsigned long) arg2; 25 + ret = 0; 64 26 break; 65 27 case ARCH_SET_GS: 66 - ret = save_registers(pid, &current->thread.regs.regs); 28 + current->thread.regs.regs.gp[GS_BASE / sizeof(unsigned long)] = 29 + (unsigned long) arg2; 30 + ret = 0; 67 31 break; 68 32 case ARCH_GET_FS: 69 - ret = put_user(tmp, arg2); 33 + ret = put_user(current->thread.regs.regs.gp[FS_BASE / sizeof(unsigned long)], arg2); 70 34 break; 71 35 case ARCH_GET_GS: 72 - ret = put_user(tmp, arg2); 36 + ret = put_user(current->thread.regs.regs.gp[GS_BASE / sizeof(unsigned long)], arg2); 73 37 break; 74 38 } 75 39 ··· 47 83 48 84 void arch_switch_to(struct task_struct *to) 49 85 { 50 - if ((to->thread.arch.fs == 0) || (to->mm == NULL)) 51 - return; 52 - 53 - arch_prctl(to, ARCH_SET_FS, (void __user *) to->thread.arch.fs); 86 + /* 87 + * Nothing needs to be done on x86_64. 88 + * The FS_BASE/GS_BASE registers are saved in the ptrace register set. 89 + */ 54 90 } 55 91 56 92 SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
+1 -1
arch/x86/um/tls_64.c
··· 12 12 * If CLONE_SETTLS is set, we need to save the thread id 13 13 * so it can be set during context switches. 14 14 */ 15 - t->thread.arch.fs = tls; 15 + t->thread.regs.regs.gp[FS_BASE / sizeof(unsigned long)] = tls; 16 16 17 17 return 0; 18 18 }