xref: /linux/arch/um/os-Linux/process.c (revision 3a24ebf0cb2ca44fdcdb5cae9ed2e778e5170f97)
11da177e4SLinus Torvalds /*
2ba180fd4SJeff Dike  * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
31da177e4SLinus Torvalds  * Licensed under the GPL
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds #include <stdio.h>
7ba180fd4SJeff Dike #include <unistd.h>
81da177e4SLinus Torvalds #include <errno.h>
91da177e4SLinus Torvalds #include <signal.h>
10512b6fb1SJeff Dike #include <fcntl.h>
111da177e4SLinus Torvalds #include <sys/mman.h>
12ba180fd4SJeff Dike #include <sys/ptrace.h>
131da177e4SLinus Torvalds #include <sys/wait.h>
14ba180fd4SJeff Dike #include <asm/unistd.h>
1536e45463SJeff Dike #include "init.h"
16ba180fd4SJeff Dike #include "kern_constants.h"
17ba180fd4SJeff Dike #include "longjmp.h"
18ba180fd4SJeff Dike #include "os.h"
19ba180fd4SJeff Dike #include "process.h"
20ba180fd4SJeff Dike #include "skas_ptrace.h"
21ba180fd4SJeff Dike #include "user.h"
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds #define ARBITRARY_ADDR -1
241da177e4SLinus Torvalds #define FAILURE_PID    -1
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #define STAT_PATH_LEN sizeof("/proc/#######/stat\0")
271da177e4SLinus Torvalds #define COMM_SCANF "%*[^)])"
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds unsigned long os_process_pc(int pid)
301da177e4SLinus Torvalds {
311da177e4SLinus Torvalds 	char proc_stat[STAT_PATH_LEN], buf[256];
32512b6fb1SJeff Dike 	unsigned long pc = ARBITRARY_ADDR;
331da177e4SLinus Torvalds 	int fd, err;
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds 	sprintf(proc_stat, "/proc/%d/stat", pid);
36512b6fb1SJeff Dike 	fd = open(proc_stat, O_RDONLY, 0);
371da177e4SLinus Torvalds 	if (fd < 0) {
38ba180fd4SJeff Dike 		printk(UM_KERN_ERR "os_process_pc - couldn't open '%s', "
39512b6fb1SJeff Dike 		       "errno = %d\n", proc_stat, errno);
40512b6fb1SJeff Dike 		goto out;
411da177e4SLinus Torvalds 	}
42a61f334fSJeff Dike 	CATCH_EINTR(err = read(fd, buf, sizeof(buf)));
431da177e4SLinus Torvalds 	if (err < 0) {
44ba180fd4SJeff Dike 		printk(UM_KERN_ERR "os_process_pc - couldn't read '%s', "
45ba180fd4SJeff Dike 		       "err = %d\n", proc_stat, errno);
46512b6fb1SJeff Dike 		goto out_close;
471da177e4SLinus Torvalds 	}
481da177e4SLinus Torvalds 	os_close_file(fd);
491da177e4SLinus Torvalds 	pc = ARBITRARY_ADDR;
501da177e4SLinus Torvalds 	if (sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d "
511da177e4SLinus Torvalds 		   "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
52512b6fb1SJeff Dike 		   "%*d %*d %*d %*d %*d %lu", &pc) != 1)
53ba180fd4SJeff Dike 		printk(UM_KERN_ERR "os_process_pc - couldn't find pc in '%s'\n",
54ba180fd4SJeff Dike 		       buf);
55512b6fb1SJeff Dike  out_close:
56512b6fb1SJeff Dike 	close(fd);
57512b6fb1SJeff Dike  out:
58ef0470c0SJeff Dike 	return pc;
591da177e4SLinus Torvalds }
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds int os_process_parent(int pid)
621da177e4SLinus Torvalds {
631da177e4SLinus Torvalds 	char stat[STAT_PATH_LEN];
641da177e4SLinus Torvalds 	char data[256];
65512b6fb1SJeff Dike 	int parent = FAILURE_PID, n, fd;
661da177e4SLinus Torvalds 
67ef0470c0SJeff Dike 	if (pid == -1)
68512b6fb1SJeff Dike 		return parent;
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 	snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
71512b6fb1SJeff Dike 	fd = open(stat, O_RDONLY, 0);
721da177e4SLinus Torvalds 	if (fd < 0) {
73512b6fb1SJeff Dike 		printk(UM_KERN_ERR "Couldn't open '%s', errno = %d\n", stat,
74512b6fb1SJeff Dike 		       errno);
75512b6fb1SJeff Dike 		return parent;
761da177e4SLinus Torvalds 	}
771da177e4SLinus Torvalds 
78a61f334fSJeff Dike 	CATCH_EINTR(n = read(fd, data, sizeof(data)));
79512b6fb1SJeff Dike 	close(fd);
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds 	if (n < 0) {
82512b6fb1SJeff Dike 		printk(UM_KERN_ERR "Couldn't read '%s', errno = %d\n", stat,
83ba180fd4SJeff Dike 		       errno);
84512b6fb1SJeff Dike 		return parent;
851da177e4SLinus Torvalds 	}
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds 	parent = FAILURE_PID;
881da177e4SLinus Torvalds 	n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent);
891da177e4SLinus Torvalds 	if (n != 1)
90ba180fd4SJeff Dike 		printk(UM_KERN_ERR "Failed to scan '%s'\n", data);
911da177e4SLinus Torvalds 
92ef0470c0SJeff Dike 	return parent;
931da177e4SLinus Torvalds }
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds void os_stop_process(int pid)
961da177e4SLinus Torvalds {
971da177e4SLinus Torvalds 	kill(pid, SIGSTOP);
981da177e4SLinus Torvalds }
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds void os_kill_process(int pid, int reap_child)
1011da177e4SLinus Torvalds {
1021da177e4SLinus Torvalds 	kill(pid, SIGKILL);
1031da177e4SLinus Torvalds 	if (reap_child)
1044dbed85aSStanislaw Gruszka 		CATCH_EINTR(waitpid(pid, NULL, __WALL));
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds 
10707f4e2c6SPaolo 'Blaisorblade' Giarrusso /* This is here uniquely to have access to the userspace errno, i.e. the one
10807f4e2c6SPaolo 'Blaisorblade' Giarrusso  * used by ptrace in case of error.
10907f4e2c6SPaolo 'Blaisorblade' Giarrusso  */
11007f4e2c6SPaolo 'Blaisorblade' Giarrusso 
11107f4e2c6SPaolo 'Blaisorblade' Giarrusso long os_ptrace_ldt(long pid, long addr, long data)
11207f4e2c6SPaolo 'Blaisorblade' Giarrusso {
11307f4e2c6SPaolo 'Blaisorblade' Giarrusso 	int ret;
11407f4e2c6SPaolo 'Blaisorblade' Giarrusso 
11507f4e2c6SPaolo 'Blaisorblade' Giarrusso 	ret = ptrace(PTRACE_LDT, pid, addr, data);
11607f4e2c6SPaolo 'Blaisorblade' Giarrusso 
11707f4e2c6SPaolo 'Blaisorblade' Giarrusso 	if (ret < 0)
11807f4e2c6SPaolo 'Blaisorblade' Giarrusso 		return -errno;
11907f4e2c6SPaolo 'Blaisorblade' Giarrusso 	return ret;
12007f4e2c6SPaolo 'Blaisorblade' Giarrusso }
12107f4e2c6SPaolo 'Blaisorblade' Giarrusso 
1221da177e4SLinus Torvalds /* Kill off a ptraced child by all means available.  kill it normally first,
1231da177e4SLinus Torvalds  * then PTRACE_KILL it, then PTRACE_CONT it in case it's in a run state from
1241da177e4SLinus Torvalds  * which it can't exit directly.
1251da177e4SLinus Torvalds  */
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds void os_kill_ptraced_process(int pid, int reap_child)
1281da177e4SLinus Torvalds {
1291da177e4SLinus Torvalds 	kill(pid, SIGKILL);
1301da177e4SLinus Torvalds 	ptrace(PTRACE_KILL, pid);
1311da177e4SLinus Torvalds 	ptrace(PTRACE_CONT, pid);
1321da177e4SLinus Torvalds 	if (reap_child)
1334dbed85aSStanislaw Gruszka 		CATCH_EINTR(waitpid(pid, NULL, __WALL));
1341da177e4SLinus Torvalds }
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds /* Don't use the glibc version, which caches the result in TLS. It misses some
13760d339f6SGennady Sharapov  * syscalls, and also breaks with clone(), which does not unshare the TLS.
13860d339f6SGennady Sharapov  */
13960d339f6SGennady Sharapov 
1401da177e4SLinus Torvalds int os_getpid(void)
1411da177e4SLinus Torvalds {
142ef0470c0SJeff Dike 	return syscall(__NR_getpid);
1431da177e4SLinus Torvalds }
1441da177e4SLinus Torvalds 
145cd2ee4a3SJeff Dike int os_getpgrp(void)
146cd2ee4a3SJeff Dike {
147cd2ee4a3SJeff Dike 	return getpgrp();
148cd2ee4a3SJeff Dike }
149cd2ee4a3SJeff Dike 
1501da177e4SLinus Torvalds int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len,
1511da177e4SLinus Torvalds 		  int r, int w, int x)
1521da177e4SLinus Torvalds {
1531da177e4SLinus Torvalds 	void *loc;
1541da177e4SLinus Torvalds 	int prot;
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
1571da177e4SLinus Torvalds 		(x ? PROT_EXEC : 0);
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 	loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
1601da177e4SLinus Torvalds 		     fd, off);
1611da177e4SLinus Torvalds 	if (loc == MAP_FAILED)
162ef0470c0SJeff Dike 		return -errno;
163ef0470c0SJeff Dike 	return 0;
1641da177e4SLinus Torvalds }
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds int os_protect_memory(void *addr, unsigned long len, int r, int w, int x)
1671da177e4SLinus Torvalds {
1681da177e4SLinus Torvalds 	int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
1691da177e4SLinus Torvalds 		    (x ? PROT_EXEC : 0));
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds 	if (mprotect(addr, len, prot) < 0)
172ef0470c0SJeff Dike 		return -errno;
173ba180fd4SJeff Dike 
174ef0470c0SJeff Dike 	return 0;
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds int os_unmap_memory(void *addr, int len)
1781da177e4SLinus Torvalds {
1791da177e4SLinus Torvalds 	int err;
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds 	err = munmap(addr, len);
1821da177e4SLinus Torvalds 	if (err < 0)
183ef0470c0SJeff Dike 		return -errno;
184ef0470c0SJeff Dike 	return 0;
1851da177e4SLinus Torvalds }
1861da177e4SLinus Torvalds 
18702dea087SJeff Dike #ifndef MADV_REMOVE
188b73781c8SJeff Dike #define MADV_REMOVE KERNEL_MADV_REMOVE
18902dea087SJeff Dike #endif
19002dea087SJeff Dike 
19197a1fcbbSJeff Dike int os_drop_memory(void *addr, int length)
19202dea087SJeff Dike {
19302dea087SJeff Dike 	int err;
19402dea087SJeff Dike 
19502dea087SJeff Dike 	err = madvise(addr, length, MADV_REMOVE);
19602dea087SJeff Dike 	if (err < 0)
19702dea087SJeff Dike 		err = -errno;
19802dea087SJeff Dike 	return err;
19902dea087SJeff Dike }
20002dea087SJeff Dike 
20136e45463SJeff Dike int __init can_drop_memory(void)
20202dea087SJeff Dike {
20302dea087SJeff Dike 	void *addr;
204e3104f50SJeff Dike 	int fd, ok = 0;
20502dea087SJeff Dike 
206ba180fd4SJeff Dike 	printk(UM_KERN_INFO "Checking host MADV_REMOVE support...");
20702dea087SJeff Dike 	fd = create_mem_file(UM_KERN_PAGE_SIZE);
20802dea087SJeff Dike 	if (fd < 0) {
209ba180fd4SJeff Dike 		printk(UM_KERN_ERR "Creating test memory file failed, "
210ba180fd4SJeff Dike 		       "err = %d\n", -fd);
211e3104f50SJeff Dike 		goto out;
21202dea087SJeff Dike 	}
21302dea087SJeff Dike 
21402dea087SJeff Dike 	addr = mmap64(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
215b73781c8SJeff Dike 		      MAP_SHARED, fd, 0);
21602dea087SJeff Dike 	if (addr == MAP_FAILED) {
217ba180fd4SJeff Dike 		printk(UM_KERN_ERR "Mapping test memory file failed, "
218ba180fd4SJeff Dike 		       "err = %d\n", -errno);
219e3104f50SJeff Dike 		goto out_close;
22002dea087SJeff Dike 	}
22102dea087SJeff Dike 
22202dea087SJeff Dike 	if (madvise(addr, UM_KERN_PAGE_SIZE, MADV_REMOVE) != 0) {
223ba180fd4SJeff Dike 		printk(UM_KERN_ERR "MADV_REMOVE failed, err = %d\n", -errno);
224e3104f50SJeff Dike 		goto out_unmap;
22502dea087SJeff Dike 	}
22602dea087SJeff Dike 
22702dea087SJeff Dike 	printk("OK\n");
228e3104f50SJeff Dike 	ok = 1;
229e3104f50SJeff Dike 
230e3104f50SJeff Dike out_unmap:
231e3104f50SJeff Dike 	munmap(addr, UM_KERN_PAGE_SIZE);
232e3104f50SJeff Dike out_close:
233e3104f50SJeff Dike 	close(fd);
234e3104f50SJeff Dike out:
235e3104f50SJeff Dike 	return ok;
23602dea087SJeff Dike }
23702dea087SJeff Dike 
238e64bd134SJeff Dike void init_new_thread_signals(void)
23960d339f6SGennady Sharapov {
240e64bd134SJeff Dike 	set_handler(SIGSEGV, (__sighandler_t) sig_handler, SA_ONSTACK,
24161b63c55SJeff Dike 		    SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
242e64bd134SJeff Dike 	set_handler(SIGTRAP, (__sighandler_t) sig_handler, SA_ONSTACK,
24361b63c55SJeff Dike 		    SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
244e64bd134SJeff Dike 	set_handler(SIGFPE, (__sighandler_t) sig_handler, SA_ONSTACK,
24561b63c55SJeff Dike 		    SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
246e64bd134SJeff Dike 	set_handler(SIGILL, (__sighandler_t) sig_handler, SA_ONSTACK,
24761b63c55SJeff Dike 		    SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
248e64bd134SJeff Dike 	set_handler(SIGBUS, (__sighandler_t) sig_handler, SA_ONSTACK,
24961b63c55SJeff Dike 		    SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
25060d339f6SGennady Sharapov 	signal(SIGHUP, SIG_IGN);
25160d339f6SGennady Sharapov 
252*3a24ebf0SJeff Dike 	set_handler(SIGIO, (__sighandler_t) sig_handler,
253*3a24ebf0SJeff Dike 		    SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGALRM,
254*3a24ebf0SJeff Dike 		    SIGVTALRM, -1);
255*3a24ebf0SJeff Dike 	signal(SIGWINCH, SIG_IGN);
25660d339f6SGennady Sharapov }
25760d339f6SGennady Sharapov 
258fab95c55SJeff Dike int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr)
25960d339f6SGennady Sharapov {
260ad28e029SJeff Dike 	jmp_buf buf;
261a5df0d1aSJeff Dike 	int n;
26260d339f6SGennady Sharapov 
26360d339f6SGennady Sharapov 	*jmp_ptr = &buf;
264a5df0d1aSJeff Dike 	n = UML_SETJMP(&buf);
26560d339f6SGennady Sharapov 	if (n != 0)
266a5df0d1aSJeff Dike 		return n;
26760d339f6SGennady Sharapov 	(*fn)(arg);
268a5df0d1aSJeff Dike 	return 0;
26960d339f6SGennady Sharapov }
270