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