Line data Source code
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 : #define ARBITRARY_ADDR -1
22 : #define FAILURE_PID -1
23 :
24 : #define STAT_PATH_LEN sizeof("/proc/#######/stat\0")
25 : #define COMM_SCANF "%*[^)])"
26 :
27 0 : unsigned long os_process_pc(int pid)
28 : {
29 : char proc_stat[STAT_PATH_LEN], buf[256];
30 0 : unsigned long pc = ARBITRARY_ADDR;
31 : int fd, err;
32 :
33 0 : sprintf(proc_stat, "/proc/%d/stat", pid);
34 0 : fd = open(proc_stat, O_RDONLY, 0);
35 0 : if (fd < 0) {
36 0 : printk(UM_KERN_ERR "os_process_pc - couldn't open '%s', "
37 : "errno = %d\n", proc_stat, errno);
38 0 : goto out;
39 : }
40 0 : CATCH_EINTR(err = read(fd, buf, sizeof(buf)));
41 0 : if (err < 0) {
42 0 : printk(UM_KERN_ERR "os_process_pc - couldn't read '%s', "
43 : "err = %d\n", proc_stat, errno);
44 0 : goto out_close;
45 : }
46 0 : os_close_file(fd);
47 0 : pc = ARBITRARY_ADDR;
48 0 : if (sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d "
49 : "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
50 : "%*d %*d %*d %*d %*d %lu", &pc) != 1)
51 0 : printk(UM_KERN_ERR "os_process_pc - couldn't find pc in '%s'\n",
52 : buf);
53 : out_close:
54 0 : close(fd);
55 : out:
56 0 : return pc;
57 : }
58 :
59 0 : int os_process_parent(int pid)
60 : {
61 : char stat[STAT_PATH_LEN];
62 : char data[256];
63 0 : int parent = FAILURE_PID, n, fd;
64 :
65 0 : if (pid == -1)
66 : return parent;
67 :
68 0 : snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
69 0 : fd = open(stat, O_RDONLY, 0);
70 0 : if (fd < 0) {
71 0 : printk(UM_KERN_ERR "Couldn't open '%s', errno = %d\n", stat,
72 : errno);
73 0 : return parent;
74 : }
75 :
76 0 : CATCH_EINTR(n = read(fd, data, sizeof(data)));
77 0 : close(fd);
78 :
79 0 : if (n < 0) {
80 0 : printk(UM_KERN_ERR "Couldn't read '%s', errno = %d\n", stat,
81 : errno);
82 0 : return parent;
83 : }
84 :
85 0 : parent = FAILURE_PID;
86 0 : n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent);
87 0 : if (n != 1)
88 0 : printk(UM_KERN_ERR "Failed to scan '%s'\n", data);
89 :
90 0 : return parent;
91 : }
92 :
93 0 : void os_alarm_process(int pid)
94 : {
95 0 : kill(pid, SIGALRM);
96 0 : }
97 :
98 0 : void os_stop_process(int pid)
99 : {
100 0 : kill(pid, SIGSTOP);
101 0 : }
102 :
103 0 : void os_kill_process(int pid, int reap_child)
104 : {
105 0 : kill(pid, SIGKILL);
106 0 : if (reap_child)
107 0 : CATCH_EINTR(waitpid(pid, NULL, __WALL));
108 0 : }
109 :
110 : /* Kill off a ptraced child by all means available. kill it normally first,
111 : * then PTRACE_KILL it, then PTRACE_CONT it in case it's in a run state from
112 : * which it can't exit directly.
113 : */
114 :
115 0 : void os_kill_ptraced_process(int pid, int reap_child)
116 : {
117 0 : kill(pid, SIGKILL);
118 0 : ptrace(PTRACE_KILL, pid);
119 0 : ptrace(PTRACE_CONT, pid);
120 0 : if (reap_child)
121 0 : CATCH_EINTR(waitpid(pid, NULL, __WALL));
122 0 : }
123 :
124 : /* Don't use the glibc version, which caches the result in TLS. It misses some
125 : * syscalls, and also breaks with clone(), which does not unshare the TLS.
126 : */
127 :
128 16 : int os_getpid(void)
129 : {
130 16 : return syscall(__NR_getpid);
131 : }
132 :
133 0 : int os_getpgrp(void)
134 : {
135 0 : return getpgrp();
136 : }
137 :
138 85020 : int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len,
139 : int r, int w, int x)
140 : {
141 : void *loc;
142 : int prot;
143 :
144 170040 : prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
145 85020 : (x ? PROT_EXEC : 0);
146 :
147 85020 : loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
148 : fd, off);
149 85020 : if (loc == MAP_FAILED)
150 0 : return -errno;
151 : return 0;
152 : }
153 :
154 0 : int os_protect_memory(void *addr, unsigned long len, int r, int w, int x)
155 : {
156 0 : int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
157 0 : (x ? PROT_EXEC : 0));
158 :
159 0 : if (mprotect(addr, len, prot) < 0)
160 0 : return -errno;
161 :
162 : return 0;
163 : }
164 :
165 85280 : int os_unmap_memory(void *addr, int len)
166 : {
167 : int err;
168 :
169 85280 : err = munmap(addr, len);
170 85280 : if (err < 0)
171 0 : return -errno;
172 : return 0;
173 : }
174 :
175 : #ifndef MADV_REMOVE
176 : #define MADV_REMOVE KERNEL_MADV_REMOVE
177 : #endif
178 :
179 0 : int os_drop_memory(void *addr, int length)
180 : {
181 : int err;
182 :
183 0 : err = madvise(addr, length, MADV_REMOVE);
184 0 : if (err < 0)
185 0 : err = -errno;
186 0 : return err;
187 : }
188 :
189 1 : int __init can_drop_memory(void)
190 : {
191 : void *addr;
192 1 : int fd, ok = 0;
193 :
194 1 : printk(UM_KERN_INFO "Checking host MADV_REMOVE support...");
195 1 : fd = create_mem_file(UM_KERN_PAGE_SIZE);
196 1 : if (fd < 0) {
197 0 : printk(UM_KERN_ERR "Creating test memory file failed, "
198 : "err = %d\n", -fd);
199 0 : goto out;
200 : }
201 :
202 1 : addr = mmap64(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
203 : MAP_SHARED, fd, 0);
204 1 : if (addr == MAP_FAILED) {
205 0 : printk(UM_KERN_ERR "Mapping test memory file failed, "
206 : "err = %d\n", -errno);
207 0 : goto out_close;
208 : }
209 :
210 1 : if (madvise(addr, UM_KERN_PAGE_SIZE, MADV_REMOVE) != 0) {
211 0 : printk(UM_KERN_ERR "MADV_REMOVE failed, err = %d\n", -errno);
212 0 : goto out_unmap;
213 : }
214 :
215 1 : printk(UM_KERN_CONT "OK\n");
216 1 : ok = 1;
217 :
218 : out_unmap:
219 1 : munmap(addr, UM_KERN_PAGE_SIZE);
220 : out_close:
221 1 : close(fd);
222 : out:
223 1 : return ok;
224 : }
225 :
226 0 : static int os_page_mincore(void *addr)
227 : {
228 : char vec[2];
229 : int ret;
230 :
231 0 : ret = mincore(addr, UM_KERN_PAGE_SIZE, vec);
232 0 : if (ret < 0) {
233 0 : if (errno == ENOMEM || errno == EINVAL)
234 : return 0;
235 : else
236 0 : return -errno;
237 : }
238 :
239 0 : return vec[0] & 1;
240 : }
241 :
242 0 : int os_mincore(void *addr, unsigned long len)
243 : {
244 : char *vec;
245 : int ret, i;
246 :
247 0 : if (len <= UM_KERN_PAGE_SIZE)
248 0 : return os_page_mincore(addr);
249 :
250 0 : vec = calloc(1, (len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE);
251 0 : if (!vec)
252 : return -ENOMEM;
253 :
254 0 : ret = mincore(addr, UM_KERN_PAGE_SIZE, vec);
255 0 : if (ret < 0) {
256 0 : if (errno == ENOMEM || errno == EINVAL)
257 : ret = 0;
258 : else
259 0 : ret = -errno;
260 :
261 : goto out;
262 : }
263 :
264 0 : for (i = 0; i < ((len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); i++) {
265 0 : if (!(vec[i] & 1)) {
266 : ret = 0;
267 : goto out;
268 : }
269 : }
270 :
271 : ret = 1;
272 : out:
273 0 : free(vec);
274 0 : return ret;
275 : }
276 :
277 1 : void init_new_thread_signals(void)
278 : {
279 1 : set_handler(SIGSEGV);
280 1 : set_handler(SIGTRAP);
281 1 : set_handler(SIGFPE);
282 1 : set_handler(SIGILL);
283 1 : set_handler(SIGBUS);
284 1 : signal(SIGHUP, SIG_IGN);
285 1 : set_handler(SIGIO);
286 1 : signal(SIGWINCH, SIG_IGN);
287 1 : }
|