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

um: Rework syscall handling

Rework syscall handling to be platform independent. Also create a clean
split between queueing of syscalls and flushing them out, removing the
need to keep state in the code that triggers the syscalls.

The code adds syscall_data_len to the global mm_id structure. This will
be used later to allow surrounding code to track whether syscalls still
need to run and if errors occurred.

Signed-off-by: Benjamin Berg <benjamin@sipsolutions.net>
Link: https://patch.msgid.link/20240703134536.1161108-5-benjamin@sipsolutions.net
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Benjamin Berg and committed by
Johannes Berg
76ed9158 542dc79f

+271 -294
+9 -13
arch/um/include/shared/os.h
··· 272 272 extern long long os_nsecs(void); 273 273 274 274 /* skas/mem.c */ 275 - extern long run_syscall_stub(struct mm_id * mm_idp, 276 - int syscall, unsigned long *args, long expected, 277 - void **addr, int done); 278 - extern long syscall_stub_data(struct mm_id * mm_idp, 279 - unsigned long *data, int data_count, 280 - void **addr, void **stub_addr); 281 - extern int map(struct mm_id * mm_idp, unsigned long virt, 282 - unsigned long len, int prot, int phys_fd, 283 - unsigned long long offset, int done, void **data); 284 - extern int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len, 285 - int done, void **data); 286 - extern int protect(struct mm_id * mm_idp, unsigned long addr, 287 - unsigned long len, unsigned int prot, int done, void **data); 275 + int syscall_stub_flush(struct mm_id *mm_idp); 276 + struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp); 277 + 278 + void map(struct mm_id *mm_idp, unsigned long virt, 279 + unsigned long len, int prot, int phys_fd, 280 + unsigned long long offset); 281 + void unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len); 282 + void protect(struct mm_id *mm_idp, unsigned long addr, 283 + unsigned long len, unsigned int prot); 288 284 289 285 /* skas/process.c */ 290 286 extern int is_skas_winch(int pid, int fd, void *data);
+1
arch/um/include/shared/skas/mm_id.h
··· 13 13 } u; 14 14 unsigned long stack; 15 15 int kill; 16 + int syscall_data_len; 16 17 }; 17 18 18 19 void __switch_mm(struct mm_id *mm_idp);
+33 -2
arch/um/include/shared/skas/stub-data.h
··· 10 10 11 11 #include <linux/compiler_types.h> 12 12 #include <as-layout.h> 13 + #include <sysdep/tls.h> 14 + 15 + #define STUB_NEXT_SYSCALL(s) \ 16 + ((struct stub_syscall *) (((unsigned long) s) + (s)->cmd_len)) 17 + 18 + enum stub_syscall_type { 19 + STUB_SYSCALL_UNSET = 0, 20 + STUB_SYSCALL_MMAP, 21 + STUB_SYSCALL_MUNMAP, 22 + STUB_SYSCALL_MPROTECT, 23 + STUB_SYSCALL_LDT, 24 + }; 25 + 26 + struct stub_syscall { 27 + union { 28 + struct { 29 + unsigned long addr; 30 + unsigned long length; 31 + unsigned long offset; 32 + int fd; 33 + int prot; 34 + } mem; 35 + struct { 36 + user_desc_t desc; 37 + int func; 38 + } ldt; 39 + }; 40 + 41 + enum stub_syscall_type syscall; 42 + }; 13 43 14 44 struct stub_data { 15 45 unsigned long offset; 16 46 int fd; 17 - long parent_err, child_err; 47 + long err, child_err; 18 48 49 + int syscall_data_len; 19 50 /* 128 leaves enough room for additional fields in the struct */ 20 - unsigned char syscall_data[UM_KERN_PAGE_SIZE - 128] __aligned(16); 51 + struct stub_syscall syscall_data[(UM_KERN_PAGE_SIZE - 128) / sizeof(struct stub_syscall)] __aligned(16); 21 52 22 53 /* Stack for our signal handlers and for calling into . */ 23 54 unsigned char sigstack[UM_KERN_PAGE_SIZE] __aligned(UM_KERN_PAGE_SIZE);
+8
arch/um/include/shared/user.h
··· 42 42 #define printk(...) _printk(__VA_ARGS__) 43 43 extern int _printk(const char *fmt, ...) 44 44 __attribute__ ((format (printf, 1, 2))); 45 + extern void print_hex_dump(const char *level, const char *prefix_str, 46 + int prefix_type, int rowsize, int groupsize, 47 + const void *buf, size_t len, _Bool ascii); 45 48 #else 46 49 static inline int printk(const char *fmt, ...) 47 50 { 48 51 return 0; 52 + } 53 + static inline void print_hex_dump(const char *level, const char *prefix_str, 54 + int prefix_type, int rowsize, int groupsize, 55 + const void *buf, size_t len, _Bool ascii) 56 + { 49 57 } 50 58 #endif 51 59
+3 -7
arch/um/kernel/exec.c
··· 22 22 23 23 void flush_thread(void) 24 24 { 25 - void *data = NULL; 26 - int ret; 27 - 28 25 arch_flush_thread(&current->thread.arch); 29 26 30 - ret = unmap(&current->mm->context.id, 0, TASK_SIZE, 1, &data); 31 - if (ret) { 32 - printk(KERN_ERR "%s - clearing address space failed, err = %d\n", 33 - __func__, ret); 27 + unmap(&current->mm->context.id, 0, TASK_SIZE); 28 + if (syscall_stub_flush(&current->mm->context.id) < 0) { 29 + printk(KERN_ERR "%s - clearing address space failed", __func__); 34 30 force_sig(SIGKILL); 35 31 } 36 32 get_safe_registers(current_pt_regs()->regs.gp,
+4 -3
arch/um/kernel/skas/Makefile
··· 3 3 # Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 4 # 5 5 6 - obj-y := clone.o mmu.o process.o syscall.o uaccess.o 6 + obj-y := clone.o stub.o mmu.o process.o syscall.o uaccess.o 7 7 8 - # clone.o is in the stub, so it can't be built with profiling 8 + # clone.o and stub.o are in the stub, so it can't be built with profiling 9 9 # GCC hardened also auto-enables -fpic, but we need %ebx so it can't work -> 10 10 # disable it 11 11 12 12 CFLAGS_clone.o := $(CFLAGS_NO_HARDENING) 13 - UNPROFILE_OBJS := clone.o 13 + CFLAGS_stub.o := $(CFLAGS_NO_HARDENING) 14 + UNPROFILE_OBJS := clone.o stub.o 14 15 15 16 KCOV_INSTRUMENT := n 16 17
+1 -1
arch/um/kernel/skas/clone.c
··· 33 33 sizeof(data->syscall_data) / 2 - 34 34 sizeof(void *)); 35 35 if (err) { 36 - data->parent_err = err; 36 + data->err = err; 37 37 goto done; 38 38 } 39 39
+80
arch/um/kernel/skas/stub.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2021 Benjamin Berg <benjamin@sipsolutions.net> 4 + */ 5 + 6 + #include <sysdep/stub.h> 7 + 8 + static __always_inline int syscall_handler(struct stub_data *d) 9 + { 10 + int i; 11 + unsigned long res; 12 + 13 + for (i = 0; i < d->syscall_data_len; i++) { 14 + struct stub_syscall *sc = &d->syscall_data[i]; 15 + 16 + switch (sc->syscall) { 17 + case STUB_SYSCALL_MMAP: 18 + res = stub_syscall6(STUB_MMAP_NR, 19 + sc->mem.addr, sc->mem.length, 20 + sc->mem.prot, 21 + MAP_SHARED | MAP_FIXED, 22 + sc->mem.fd, sc->mem.offset); 23 + if (res != sc->mem.addr) { 24 + d->err = res; 25 + d->syscall_data_len = i; 26 + return -1; 27 + } 28 + break; 29 + case STUB_SYSCALL_MUNMAP: 30 + res = stub_syscall2(__NR_munmap, 31 + sc->mem.addr, sc->mem.length); 32 + if (res) { 33 + d->err = res; 34 + d->syscall_data_len = i; 35 + return -1; 36 + } 37 + break; 38 + case STUB_SYSCALL_MPROTECT: 39 + res = stub_syscall3(__NR_mprotect, 40 + sc->mem.addr, sc->mem.length, 41 + sc->mem.prot); 42 + if (res) { 43 + d->err = res; 44 + d->syscall_data_len = i; 45 + return -1; 46 + } 47 + break; 48 + case STUB_SYSCALL_LDT: 49 + res = stub_syscall3(__NR_modify_ldt, sc->ldt.func, 50 + (unsigned long) &sc->ldt.desc, 51 + sizeof(sc->ldt.desc)); 52 + /* We only write, so the expected result is zero */ 53 + if (res) { 54 + d->err = res; 55 + d->syscall_data_len = i; 56 + return -1; 57 + } 58 + break; 59 + default: 60 + d->err = -95; /* EOPNOTSUPP */ 61 + d->syscall_data_len = i; 62 + return -1; 63 + } 64 + } 65 + 66 + d->err = 0; 67 + d->syscall_data_len = 0; 68 + 69 + return 0; 70 + } 71 + 72 + void __section(".__syscall_stub") 73 + stub_syscall_handler(void) 74 + { 75 + struct stub_data *d = get_stub_data(); 76 + 77 + syscall_handler(d); 78 + 79 + trap_myself(); 80 + }
+20 -22
arch/um/kernel/tlb.c
··· 71 71 switch (op->type) { 72 72 case MMAP: 73 73 if (hvc->userspace) 74 - ret = map(&hvc->mm->context.id, op->u.mmap.addr, 75 - op->u.mmap.len, op->u.mmap.prot, 76 - op->u.mmap.fd, 77 - op->u.mmap.offset, finished, 78 - &hvc->data); 74 + map(&hvc->mm->context.id, op->u.mmap.addr, 75 + op->u.mmap.len, op->u.mmap.prot, 76 + op->u.mmap.fd, 77 + op->u.mmap.offset); 79 78 else 80 79 map_memory(op->u.mmap.addr, op->u.mmap.offset, 81 80 op->u.mmap.len, 1, 1, 1); 82 81 break; 83 82 case MUNMAP: 84 83 if (hvc->userspace) 85 - ret = unmap(&hvc->mm->context.id, 86 - op->u.munmap.addr, 87 - op->u.munmap.len, finished, 88 - &hvc->data); 84 + unmap(&hvc->mm->context.id, 85 + op->u.munmap.addr, 86 + op->u.munmap.len); 89 87 else 90 88 ret = os_unmap_memory( 91 89 (void *) op->u.munmap.addr, ··· 92 94 break; 93 95 case MPROTECT: 94 96 if (hvc->userspace) 95 - ret = protect(&hvc->mm->context.id, 96 - op->u.mprotect.addr, 97 - op->u.mprotect.len, 98 - op->u.mprotect.prot, 99 - finished, &hvc->data); 97 + protect(&hvc->mm->context.id, 98 + op->u.mprotect.addr, 99 + op->u.mprotect.len, 100 + op->u.mprotect.prot); 100 101 else 101 102 ret = os_protect_memory( 102 103 (void *) op->u.mprotect.addr, ··· 109 112 break; 110 113 } 111 114 } 115 + 116 + if (hvc->userspace && finished) 117 + ret = syscall_stub_flush(&hvc->mm->context.id); 112 118 113 119 if (ret == -ENOMEM) 114 120 report_enomem(); ··· 461 461 pmd_t *pmd; 462 462 pte_t *pte; 463 463 struct mm_struct *mm = vma->vm_mm; 464 - void *flush = NULL; 465 464 int r, w, x, prot, err = 0; 466 465 struct mm_id *mm_id; 467 466 ··· 503 504 int fd; 504 505 505 506 fd = phys_mapping(pte_val(*pte) & PAGE_MASK, &offset); 506 - err = map(mm_id, address, PAGE_SIZE, prot, fd, offset, 507 - 1, &flush); 508 - } 509 - else err = unmap(mm_id, address, PAGE_SIZE, 1, &flush); 510 - } 511 - else if (pte_newprot(*pte)) 512 - err = protect(mm_id, address, PAGE_SIZE, prot, 1, &flush); 507 + map(mm_id, address, PAGE_SIZE, prot, fd, offset); 508 + } else 509 + unmap(mm_id, address, PAGE_SIZE); 510 + } else if (pte_newprot(*pte)) 511 + protect(mm_id, address, PAGE_SIZE, prot); 513 512 513 + err = syscall_stub_flush(mm_id); 514 514 if (err) { 515 515 if (err == -ENOMEM) 516 516 report_enomem();
+94 -110
arch/um/os-Linux/skas/mem.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* 3 + * Copyright (C) 2021 Benjamin Berg <benjamin@sipsolutions.net> 3 4 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 4 5 */ 5 6 ··· 20 19 #include <sysdep/stub.h> 21 20 #include "../internal.h" 22 21 23 - extern char batch_syscall_stub[], __syscall_stub_start[]; 22 + extern char __syscall_stub_start[]; 24 23 25 24 static inline unsigned long *check_init_stack(struct mm_id * mm_idp, 26 25 unsigned long *stack) ··· 37 36 static int __init init_syscall_regs(void) 38 37 { 39 38 get_safe_registers(syscall_regs, NULL); 39 + 40 40 syscall_regs[REGS_IP_INDEX] = STUB_CODE + 41 - ((unsigned long) batch_syscall_stub - 41 + ((unsigned long) stub_syscall_handler - 42 42 (unsigned long) __syscall_stub_start); 43 - syscall_regs[REGS_SP_INDEX] = STUB_DATA; 43 + syscall_regs[REGS_SP_INDEX] = STUB_DATA + 44 + offsetof(struct stub_data, sigstack) + 45 + sizeof(((struct stub_data *) 0)->sigstack) - 46 + sizeof(void *); 44 47 45 48 return 0; 46 49 } 47 50 48 51 __initcall(init_syscall_regs); 49 52 50 - static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) 53 + static inline long do_syscall_stub(struct mm_id *mm_idp) 51 54 { 55 + struct stub_data *proc_data = (void *)mm_idp->stack; 52 56 int n, i; 53 - long ret, offset; 54 - unsigned long * data; 55 - unsigned long * syscall; 56 57 int err, pid = mm_idp->u.pid; 57 58 58 59 n = ptrace_setregs(pid, syscall_regs); ··· 66 63 __func__, -n); 67 64 } 68 65 66 + /* Inform process how much we have filled in. */ 67 + proc_data->syscall_data_len = mm_idp->syscall_data_len; 68 + 69 69 err = ptrace(PTRACE_CONT, pid, 0, 0); 70 70 if (err) 71 71 panic("Failed to continue stub, pid = %d, errno = %d\n", pid, ··· 77 71 wait_stub_done(pid); 78 72 79 73 /* 80 - * When the stub stops, we find the following values on the 81 - * beginning of the stack: 82 - * (long )return_value 83 - * (long )offset to failed sycall-data (0, if no error) 74 + * proc_data->err will be non-zero if there was an (unexpected) error. 75 + * In that case, syscall_data_len points to the last executed syscall, 76 + * otherwise it will be zero (but we do not need to rely on that). 84 77 */ 85 - ret = *((unsigned long *) mm_idp->stack); 86 - offset = *((unsigned long *) mm_idp->stack + 1); 87 - if (offset) { 88 - data = (unsigned long *)(mm_idp->stack + offset - STUB_DATA); 89 - printk(UM_KERN_ERR "%s : ret = %ld, offset = %ld, data = %p\n", 90 - __func__, ret, offset, data); 91 - syscall = (unsigned long *)((unsigned long)data + data[0]); 92 - printk(UM_KERN_ERR "%s: syscall %ld failed, return value = 0x%lx, expected return value = 0x%lx\n", 93 - __func__, syscall[0], ret, syscall[7]); 94 - printk(UM_KERN_ERR " syscall parameters: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", 95 - syscall[1], syscall[2], syscall[3], 96 - syscall[4], syscall[5], syscall[6]); 97 - for (n = 1; n < data[0]/sizeof(long); n++) { 98 - if (n == 1) 99 - printk(UM_KERN_ERR " additional syscall data:"); 100 - if (n % 4 == 1) 101 - printk("\n" UM_KERN_ERR " "); 102 - printk(" 0x%lx", data[n]); 103 - } 104 - if (n > 1) 105 - printk("\n"); 78 + if (proc_data->err < 0) { 79 + struct stub_syscall *sc; 80 + 81 + if (proc_data->syscall_data_len < 0 || 82 + proc_data->syscall_data_len >= ARRAY_SIZE(proc_data->syscall_data)) 83 + panic("Syscall data was corrupted by stub (len is: %d, expected maximum: %d)!", 84 + proc_data->syscall_data_len, 85 + mm_idp->syscall_data_len); 86 + 87 + sc = &proc_data->syscall_data[proc_data->syscall_data_len]; 88 + 89 + printk(UM_KERN_ERR "%s : length = %d, last offset = %d", 90 + __func__, mm_idp->syscall_data_len, 91 + proc_data->syscall_data_len); 92 + printk(UM_KERN_ERR "%s : stub syscall type %d failed, return value = 0x%lx\n", 93 + __func__, sc->syscall, proc_data->err); 94 + 95 + print_hex_dump(UM_KERN_ERR, 96 + " syscall data: ", 0, 97 + 16, 4, sc, sizeof(*sc), 0); 98 + 99 + mm_idp->syscall_data_len = proc_data->err; 100 + } else { 101 + mm_idp->syscall_data_len = 0; 106 102 } 107 - else ret = 0; 108 103 109 - *addr = check_init_stack(mm_idp, NULL); 110 - 111 - return ret; 104 + return mm_idp->syscall_data_len; 112 105 } 113 106 114 - long run_syscall_stub(struct mm_id * mm_idp, int syscall, 115 - unsigned long *args, long expected, void **addr, 116 - int done) 107 + int syscall_stub_flush(struct mm_id *mm_idp) 117 108 { 118 - unsigned long *stack = check_init_stack(mm_idp, *addr); 109 + int res; 119 110 120 - *stack += sizeof(long); 121 - stack += *stack / sizeof(long); 122 - 123 - *stack++ = syscall; 124 - *stack++ = args[0]; 125 - *stack++ = args[1]; 126 - *stack++ = args[2]; 127 - *stack++ = args[3]; 128 - *stack++ = args[4]; 129 - *stack++ = args[5]; 130 - *stack++ = expected; 131 - *stack = 0; 132 - 133 - if (!done && ((((unsigned long) stack) & ~UM_KERN_PAGE_MASK) < 134 - UM_KERN_PAGE_SIZE - 10 * sizeof(long))) { 135 - *addr = stack; 111 + if (mm_idp->syscall_data_len == 0) 136 112 return 0; 113 + 114 + /* If an error happened already, report it and reset the state. */ 115 + if (mm_idp->syscall_data_len < 0) { 116 + res = mm_idp->syscall_data_len; 117 + mm_idp->syscall_data_len = 0; 118 + return res; 137 119 } 138 120 139 - return do_syscall_stub(mm_idp, addr); 121 + res = do_syscall_stub(mm_idp); 122 + mm_idp->syscall_data_len = 0; 123 + 124 + return res; 140 125 } 141 126 142 - long syscall_stub_data(struct mm_id * mm_idp, 143 - unsigned long *data, int data_count, 144 - void **addr, void **stub_addr) 127 + struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp) 145 128 { 146 - unsigned long *stack; 147 - int ret = 0; 129 + struct stub_syscall *sc; 130 + struct stub_data *proc_data = (struct stub_data *) mm_idp->stack; 148 131 149 - /* 150 - * If *addr still is uninitialized, it *must* contain NULL. 151 - * Thus in this case do_syscall_stub correctly won't be called. 152 - */ 153 - if ((((unsigned long) *addr) & ~UM_KERN_PAGE_MASK) >= 154 - UM_KERN_PAGE_SIZE - (10 + data_count) * sizeof(long)) { 155 - ret = do_syscall_stub(mm_idp, addr); 156 - /* in case of error, don't overwrite data on stack */ 157 - if (ret) 158 - return ret; 132 + if (mm_idp->syscall_data_len > 0 && 133 + mm_idp->syscall_data_len == ARRAY_SIZE(proc_data->syscall_data)) 134 + do_syscall_stub(mm_idp); 135 + 136 + if (mm_idp->syscall_data_len < 0) { 137 + /* Return dummy to retain error state. */ 138 + sc = &proc_data->syscall_data[0]; 139 + } else { 140 + sc = &proc_data->syscall_data[mm_idp->syscall_data_len]; 141 + mm_idp->syscall_data_len += 1; 159 142 } 143 + memset(sc, 0, sizeof(*sc)); 160 144 161 - stack = check_init_stack(mm_idp, *addr); 162 - *addr = stack; 163 - 164 - *stack = data_count * sizeof(long); 165 - 166 - memcpy(stack + 1, data, data_count * sizeof(long)); 167 - 168 - *stub_addr = (void *)(((unsigned long)(stack + 1) & 169 - ~UM_KERN_PAGE_MASK) + STUB_DATA); 170 - 171 - return 0; 145 + return sc; 172 146 } 173 147 174 - int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, int prot, 175 - int phys_fd, unsigned long long offset, int done, void **data) 148 + 149 + void map(struct mm_id *mm_idp, unsigned long virt, unsigned long len, int prot, 150 + int phys_fd, unsigned long long offset) 176 151 { 177 - int ret; 178 - unsigned long args[] = { virt, len, prot, 179 - MAP_SHARED | MAP_FIXED, phys_fd, 180 - MMAP_OFFSET(offset) }; 152 + struct stub_syscall *sc; 181 153 182 - ret = run_syscall_stub(mm_idp, STUB_MMAP_NR, args, virt, 183 - data, done); 184 - 185 - return ret; 154 + sc = syscall_stub_alloc(mm_idp); 155 + sc->syscall = STUB_SYSCALL_MMAP; 156 + sc->mem.addr = virt; 157 + sc->mem.length = len; 158 + sc->mem.prot = prot; 159 + sc->mem.fd = phys_fd; 160 + sc->mem.offset = MMAP_OFFSET(offset); 186 161 } 187 162 188 - int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len, 189 - int done, void **data) 163 + void unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len) 190 164 { 191 - int ret; 192 - unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0, 193 - 0 }; 165 + struct stub_syscall *sc; 194 166 195 - ret = run_syscall_stub(mm_idp, __NR_munmap, args, 0, 196 - data, done); 197 - 198 - return ret; 167 + sc = syscall_stub_alloc(mm_idp); 168 + sc->syscall = STUB_SYSCALL_MUNMAP; 169 + sc->mem.addr = addr; 170 + sc->mem.length = len; 199 171 } 200 172 201 - int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, 202 - unsigned int prot, int done, void **data) 173 + void protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len, 174 + unsigned int prot) 203 175 { 204 - int ret; 205 - unsigned long args[] = { addr, len, prot, 0, 0, 0 }; 176 + struct stub_syscall *sc; 206 177 207 - ret = run_syscall_stub(mm_idp, __NR_mprotect, args, 0, 208 - data, done); 209 - 210 - return ret; 178 + sc = syscall_stub_alloc(mm_idp); 179 + sc->syscall = STUB_SYSCALL_MPROTECT; 180 + sc->mem.addr = addr; 181 + sc->mem.length = len; 182 + sc->mem.prot = prot; 211 183 }
+2 -2
arch/um/os-Linux/skas/process.c
··· 501 501 *data = ((struct stub_data) { 502 502 .offset = MMAP_OFFSET(new_offset), 503 503 .fd = new_fd, 504 - .parent_err = -ESRCH, 504 + .err = -ESRCH, 505 505 .child_err = 0, 506 506 }); 507 507 ··· 538 538 539 539 wait_stub_done(pid); 540 540 541 - pid = data->parent_err; 541 + pid = data->err; 542 542 if (pid < 0) { 543 543 printk(UM_KERN_ERR "%s - stub-parent reports error %d\n", 544 544 __func__, -pid);
+1 -1
arch/x86/um/Makefile
··· 11 11 12 12 obj-y = bugs_$(BITS).o delay.o fault.o ldt.o \ 13 13 ptrace_$(BITS).o ptrace_user.o setjmp_$(BITS).o signal.o \ 14 - stub_$(BITS).o stub_segv.o \ 14 + stub_segv.o \ 15 15 sys_call_table_$(BITS).o sysrq_$(BITS).o tls_$(BITS).o \ 16 16 mem_$(BITS).o subarch.o os-Linux/ 17 17
+14 -27
arch/x86/um/ldt.c
··· 12 12 #include <os.h> 13 13 #include <skas.h> 14 14 #include <sysdep/tls.h> 15 + #include <stub-data.h> 15 16 16 17 static inline int modify_ldt (int func, void *ptr, unsigned long bytecount) 17 18 { 18 19 return syscall(__NR_modify_ldt, func, ptr, bytecount); 19 20 } 20 21 21 - static long write_ldt_entry(struct mm_id *mm_idp, int func, 22 - struct user_desc *desc, void **addr, int done) 22 + static void write_ldt_entry(struct mm_id *mm_idp, int func, 23 + struct user_desc *desc) 23 24 { 24 - long res; 25 - void *stub_addr; 25 + struct stub_syscall *sc; 26 26 27 - BUILD_BUG_ON(sizeof(*desc) % sizeof(long)); 28 - 29 - res = syscall_stub_data(mm_idp, (unsigned long *)desc, 30 - sizeof(*desc) / sizeof(long), 31 - addr, &stub_addr); 32 - if (!res) { 33 - unsigned long args[] = { func, 34 - (unsigned long)stub_addr, 35 - sizeof(*desc), 36 - 0, 0, 0 }; 37 - res = run_syscall_stub(mm_idp, __NR_modify_ldt, args, 38 - 0, addr, done); 39 - } 40 - 41 - return res; 27 + sc = syscall_stub_alloc(mm_idp); 28 + sc->syscall = STUB_SYSCALL_LDT; 29 + sc->ldt.func = func; 30 + memcpy(&sc->ldt.desc, desc, sizeof(*desc)); 42 31 } 43 32 44 33 /* ··· 116 127 int i, err; 117 128 struct user_desc ldt_info; 118 129 struct ldt_entry entry0, *ldt_p; 119 - void *addr = NULL; 120 130 121 131 err = -EINVAL; 122 132 if (bytecount != sizeof(ldt_info)) ··· 136 148 137 149 mutex_lock(&ldt->lock); 138 150 139 - err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1); 151 + write_ldt_entry(mm_idp, func, &ldt_info); 152 + err = syscall_stub_flush(mm_idp); 140 153 if (err) 141 154 goto out_unlock; 142 155 ··· 155 166 err = -ENOMEM; 156 167 /* Undo the change in host */ 157 168 memset(&ldt_info, 0, sizeof(ldt_info)); 158 - write_ldt_entry(mm_idp, 1, &ldt_info, &addr, 1); 169 + write_ldt_entry(mm_idp, 1, &ldt_info); 170 + err = syscall_stub_flush(mm_idp); 159 171 goto out_unlock; 160 172 } 161 173 if (i == 0) { ··· 293 303 short * num_p; 294 304 int i; 295 305 long page, err=0; 296 - void *addr = NULL; 297 306 298 307 299 308 mutex_init(&new_mm->arch.ldt.lock); ··· 307 318 ldt_get_host_info(); 308 319 for (num_p=host_ldt_entries; *num_p != -1; num_p++) { 309 320 desc.entry_number = *num_p; 310 - err = write_ldt_entry(&new_mm->id, 1, &desc, 311 - &addr, *(num_p + 1) == -1); 312 - if (err) 313 - break; 321 + write_ldt_entry(&new_mm->id, 1, &desc); 314 322 } 323 + err = syscall_stub_flush(&new_mm->id); 315 324 new_mm->arch.ldt.entry_count = 0; 316 325 317 326 goto out;
+1
arch/x86/um/shared/sysdep/stub.h
··· 12 12 #endif 13 13 14 14 extern void stub_segv_handler(int, siginfo_t *, void *); 15 + extern void stub_syscall_handler(void); 15 16 extern void stub_clone_handler(void);
-56
arch/x86/um/stub_32.S
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - #include <as-layout.h> 3 - 4 - .section .__syscall_stub, "ax" 5 - 6 - .globl batch_syscall_stub 7 - batch_syscall_stub: 8 - /* %esp comes in as "top of page" */ 9 - mov %esp, %ecx 10 - /* %esp has pointer to first operation */ 11 - add $8, %esp 12 - again: 13 - /* load length of additional data */ 14 - mov 0x0(%esp), %eax 15 - 16 - /* if(length == 0) : end of list */ 17 - /* write possible 0 to header */ 18 - mov %eax, 0x4(%ecx) 19 - cmpl $0, %eax 20 - jz done 21 - 22 - /* save current pointer */ 23 - mov %esp, 0x4(%ecx) 24 - 25 - /* skip additional data */ 26 - add %eax, %esp 27 - 28 - /* load syscall-# */ 29 - pop %eax 30 - 31 - /* load syscall params */ 32 - pop %ebx 33 - pop %ecx 34 - pop %edx 35 - pop %esi 36 - pop %edi 37 - pop %ebp 38 - 39 - /* execute syscall */ 40 - int $0x80 41 - 42 - /* restore top of page pointer in %ecx */ 43 - mov %esp, %ecx 44 - andl $(~UM_KERN_PAGE_SIZE) + 1, %ecx 45 - 46 - /* check return value */ 47 - pop %ebx 48 - cmp %ebx, %eax 49 - je again 50 - 51 - done: 52 - /* save return value */ 53 - mov %eax, (%ecx) 54 - 55 - /* stop */ 56 - int3
-50
arch/x86/um/stub_64.S
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - #include <as-layout.h> 3 - 4 - .section .__syscall_stub, "ax" 5 - .globl batch_syscall_stub 6 - batch_syscall_stub: 7 - /* %rsp has the pointer to first operation */ 8 - mov %rsp, %rbx 9 - add $0x10, %rsp 10 - again: 11 - /* load length of additional data */ 12 - mov 0x0(%rsp), %rax 13 - 14 - /* if(length == 0) : end of list */ 15 - /* write possible 0 to header */ 16 - mov %rax, 8(%rbx) 17 - cmp $0, %rax 18 - jz done 19 - 20 - /* save current pointer */ 21 - mov %rsp, 8(%rbx) 22 - 23 - /* skip additional data */ 24 - add %rax, %rsp 25 - 26 - /* load syscall-# */ 27 - pop %rax 28 - 29 - /* load syscall params */ 30 - pop %rdi 31 - pop %rsi 32 - pop %rdx 33 - pop %r10 34 - pop %r8 35 - pop %r9 36 - 37 - /* execute syscall */ 38 - syscall 39 - 40 - /* check return value */ 41 - pop %rcx 42 - cmp %rcx, %rax 43 - je again 44 - 45 - done: 46 - /* save return value */ 47 - mov %rax, (%rbx) 48 - 49 - /* stop */ 50 - int3