1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de) 4 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 5 */ 6 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <unistd.h> 10 #include <errno.h> 11 #include <signal.h> 12 #include <fcntl.h> 13 #include <sys/mman.h> 14 #include <sys/ptrace.h> 15 #include <sys/wait.h> 16 #include <asm/unistd.h> 17 #include <init.h> 18 #include <longjmp.h> 19 #include <os.h> 20 21 void os_alarm_process(int pid) 22 { 23 kill(pid, SIGALRM); 24 } 25 26 void os_kill_process(int pid, int reap_child) 27 { 28 kill(pid, SIGKILL); 29 if (reap_child) 30 CATCH_EINTR(waitpid(pid, NULL, __WALL)); 31 } 32 33 /* Kill off a ptraced child by all means available. kill it normally first, 34 * then PTRACE_KILL it, then PTRACE_CONT it in case it's in a run state from 35 * which it can't exit directly. 36 */ 37 38 void os_kill_ptraced_process(int pid, int reap_child) 39 { 40 kill(pid, SIGKILL); 41 ptrace(PTRACE_KILL, pid); 42 ptrace(PTRACE_CONT, pid); 43 if (reap_child) 44 CATCH_EINTR(waitpid(pid, NULL, __WALL)); 45 } 46 47 /* Don't use the glibc version, which caches the result in TLS. It misses some 48 * syscalls, and also breaks with clone(), which does not unshare the TLS. 49 */ 50 51 int os_getpid(void) 52 { 53 return syscall(__NR_getpid); 54 } 55 56 int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, 57 int r, int w, int x) 58 { 59 void *loc; 60 int prot; 61 62 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 63 (x ? PROT_EXEC : 0); 64 65 loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, 66 fd, off); 67 if (loc == MAP_FAILED) 68 return -errno; 69 return 0; 70 } 71 72 int os_protect_memory(void *addr, unsigned long len, int r, int w, int x) 73 { 74 int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 75 (x ? PROT_EXEC : 0)); 76 77 if (mprotect(addr, len, prot) < 0) 78 return -errno; 79 80 return 0; 81 } 82 83 int os_unmap_memory(void *addr, int len) 84 { 85 int err; 86 87 err = munmap(addr, len); 88 if (err < 0) 89 return -errno; 90 return 0; 91 } 92 93 #ifndef MADV_REMOVE 94 #define MADV_REMOVE KERNEL_MADV_REMOVE 95 #endif 96 97 int os_drop_memory(void *addr, int length) 98 { 99 int err; 100 101 err = madvise(addr, length, MADV_REMOVE); 102 if (err < 0) 103 err = -errno; 104 return err; 105 } 106 107 int __init can_drop_memory(void) 108 { 109 void *addr; 110 int fd, ok = 0; 111 112 printk(UM_KERN_INFO "Checking host MADV_REMOVE support..."); 113 fd = create_mem_file(UM_KERN_PAGE_SIZE); 114 if (fd < 0) { 115 printk(UM_KERN_ERR "Creating test memory file failed, " 116 "err = %d\n", -fd); 117 goto out; 118 } 119 120 addr = mmap64(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, 121 MAP_SHARED, fd, 0); 122 if (addr == MAP_FAILED) { 123 printk(UM_KERN_ERR "Mapping test memory file failed, " 124 "err = %d\n", -errno); 125 goto out_close; 126 } 127 128 if (madvise(addr, UM_KERN_PAGE_SIZE, MADV_REMOVE) != 0) { 129 printk(UM_KERN_ERR "MADV_REMOVE failed, err = %d\n", -errno); 130 goto out_unmap; 131 } 132 133 printk(UM_KERN_CONT "OK\n"); 134 ok = 1; 135 136 out_unmap: 137 munmap(addr, UM_KERN_PAGE_SIZE); 138 out_close: 139 close(fd); 140 out: 141 return ok; 142 } 143 144 static int os_page_mincore(void *addr) 145 { 146 char vec[2]; 147 int ret; 148 149 ret = mincore(addr, UM_KERN_PAGE_SIZE, vec); 150 if (ret < 0) { 151 if (errno == ENOMEM || errno == EINVAL) 152 return 0; 153 else 154 return -errno; 155 } 156 157 return vec[0] & 1; 158 } 159 160 int os_mincore(void *addr, unsigned long len) 161 { 162 char *vec; 163 int ret, i; 164 165 if (len <= UM_KERN_PAGE_SIZE) 166 return os_page_mincore(addr); 167 168 vec = calloc(1, (len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); 169 if (!vec) 170 return -ENOMEM; 171 172 ret = mincore(addr, UM_KERN_PAGE_SIZE, vec); 173 if (ret < 0) { 174 if (errno == ENOMEM || errno == EINVAL) 175 ret = 0; 176 else 177 ret = -errno; 178 179 goto out; 180 } 181 182 for (i = 0; i < ((len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); i++) { 183 if (!(vec[i] & 1)) { 184 ret = 0; 185 goto out; 186 } 187 } 188 189 ret = 1; 190 out: 191 free(vec); 192 return ret; 193 } 194 195 void init_new_thread_signals(void) 196 { 197 set_handler(SIGSEGV); 198 set_handler(SIGTRAP); 199 set_handler(SIGFPE); 200 set_handler(SIGILL); 201 set_handler(SIGBUS); 202 signal(SIGHUP, SIG_IGN); 203 set_handler(SIGIO); 204 signal(SIGWINCH, SIG_IGN); 205 } 206