1*97870c34SAlex Dewar // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
32eb5f31bSAnton Ivanov * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
4ba180fd4SJeff Dike * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
51da177e4SLinus Torvalds */
61da177e4SLinus Torvalds
71da177e4SLinus Torvalds #include <stdio.h>
8f75b1b1bSRichard Weinberger #include <stdlib.h>
9ba180fd4SJeff Dike #include <unistd.h>
101da177e4SLinus Torvalds #include <errno.h>
111da177e4SLinus Torvalds #include <signal.h>
12512b6fb1SJeff Dike #include <fcntl.h>
131da177e4SLinus Torvalds #include <sys/mman.h>
14ba180fd4SJeff Dike #include <sys/ptrace.h>
151da177e4SLinus Torvalds #include <sys/wait.h>
16ba180fd4SJeff Dike #include <asm/unistd.h>
1737185b33SAl Viro #include <init.h>
1837185b33SAl Viro #include <longjmp.h>
1937185b33SAl Viro #include <os.h>
201da177e4SLinus Torvalds
211da177e4SLinus Torvalds #define ARBITRARY_ADDR -1
221da177e4SLinus Torvalds #define FAILURE_PID -1
231da177e4SLinus Torvalds
241da177e4SLinus Torvalds #define STAT_PATH_LEN sizeof("/proc/#######/stat\0")
251da177e4SLinus Torvalds #define COMM_SCANF "%*[^)])"
261da177e4SLinus Torvalds
os_process_pc(int pid)271da177e4SLinus Torvalds unsigned long os_process_pc(int pid)
281da177e4SLinus Torvalds {
291da177e4SLinus Torvalds char proc_stat[STAT_PATH_LEN], buf[256];
30512b6fb1SJeff Dike unsigned long pc = ARBITRARY_ADDR;
311da177e4SLinus Torvalds int fd, err;
321da177e4SLinus Torvalds
331da177e4SLinus Torvalds sprintf(proc_stat, "/proc/%d/stat", pid);
34512b6fb1SJeff Dike fd = open(proc_stat, O_RDONLY, 0);
351da177e4SLinus Torvalds if (fd < 0) {
36ba180fd4SJeff Dike printk(UM_KERN_ERR "os_process_pc - couldn't open '%s', "
37512b6fb1SJeff Dike "errno = %d\n", proc_stat, errno);
38512b6fb1SJeff Dike goto out;
391da177e4SLinus Torvalds }
40a61f334fSJeff Dike CATCH_EINTR(err = read(fd, buf, sizeof(buf)));
411da177e4SLinus Torvalds if (err < 0) {
42ba180fd4SJeff Dike printk(UM_KERN_ERR "os_process_pc - couldn't read '%s', "
43ba180fd4SJeff Dike "err = %d\n", proc_stat, errno);
44512b6fb1SJeff Dike goto out_close;
451da177e4SLinus Torvalds }
461da177e4SLinus Torvalds os_close_file(fd);
471da177e4SLinus Torvalds pc = ARBITRARY_ADDR;
481da177e4SLinus Torvalds if (sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d "
491da177e4SLinus Torvalds "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
50512b6fb1SJeff Dike "%*d %*d %*d %*d %*d %lu", &pc) != 1)
51ba180fd4SJeff Dike printk(UM_KERN_ERR "os_process_pc - couldn't find pc in '%s'\n",
52ba180fd4SJeff Dike buf);
53512b6fb1SJeff Dike out_close:
54512b6fb1SJeff Dike close(fd);
55512b6fb1SJeff Dike out:
56ef0470c0SJeff Dike return pc;
571da177e4SLinus Torvalds }
581da177e4SLinus Torvalds
os_process_parent(int pid)591da177e4SLinus Torvalds int os_process_parent(int pid)
601da177e4SLinus Torvalds {
611da177e4SLinus Torvalds char stat[STAT_PATH_LEN];
621da177e4SLinus Torvalds char data[256];
63512b6fb1SJeff Dike int parent = FAILURE_PID, n, fd;
641da177e4SLinus Torvalds
65ef0470c0SJeff Dike if (pid == -1)
66512b6fb1SJeff Dike return parent;
671da177e4SLinus Torvalds
681da177e4SLinus Torvalds snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
69512b6fb1SJeff Dike fd = open(stat, O_RDONLY, 0);
701da177e4SLinus Torvalds if (fd < 0) {
71512b6fb1SJeff Dike printk(UM_KERN_ERR "Couldn't open '%s', errno = %d\n", stat,
72512b6fb1SJeff Dike errno);
73512b6fb1SJeff Dike return parent;
741da177e4SLinus Torvalds }
751da177e4SLinus Torvalds
76a61f334fSJeff Dike CATCH_EINTR(n = read(fd, data, sizeof(data)));
77512b6fb1SJeff Dike close(fd);
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds if (n < 0) {
80512b6fb1SJeff Dike printk(UM_KERN_ERR "Couldn't read '%s', errno = %d\n", stat,
81ba180fd4SJeff Dike errno);
82512b6fb1SJeff Dike return parent;
831da177e4SLinus Torvalds }
841da177e4SLinus Torvalds
851da177e4SLinus Torvalds parent = FAILURE_PID;
861da177e4SLinus Torvalds n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent);
871da177e4SLinus Torvalds if (n != 1)
88ba180fd4SJeff Dike printk(UM_KERN_ERR "Failed to scan '%s'\n", data);
891da177e4SLinus Torvalds
90ef0470c0SJeff Dike return parent;
911da177e4SLinus Torvalds }
921da177e4SLinus Torvalds
os_alarm_process(int pid)932eb5f31bSAnton Ivanov void os_alarm_process(int pid)
942eb5f31bSAnton Ivanov {
952eb5f31bSAnton Ivanov kill(pid, SIGALRM);
962eb5f31bSAnton Ivanov }
972eb5f31bSAnton Ivanov
os_stop_process(int pid)981da177e4SLinus Torvalds void os_stop_process(int pid)
991da177e4SLinus Torvalds {
1001da177e4SLinus Torvalds kill(pid, SIGSTOP);
1011da177e4SLinus Torvalds }
1021da177e4SLinus Torvalds
os_kill_process(int pid,int reap_child)1031da177e4SLinus Torvalds void os_kill_process(int pid, int reap_child)
1041da177e4SLinus Torvalds {
1051da177e4SLinus Torvalds kill(pid, SIGKILL);
1061da177e4SLinus Torvalds if (reap_child)
1074dbed85aSStanislaw Gruszka CATCH_EINTR(waitpid(pid, NULL, __WALL));
1081da177e4SLinus Torvalds }
1091da177e4SLinus Torvalds
1101da177e4SLinus Torvalds /* Kill off a ptraced child by all means available. kill it normally first,
1111da177e4SLinus Torvalds * then PTRACE_KILL it, then PTRACE_CONT it in case it's in a run state from
1121da177e4SLinus Torvalds * which it can't exit directly.
1131da177e4SLinus Torvalds */
1141da177e4SLinus Torvalds
os_kill_ptraced_process(int pid,int reap_child)1151da177e4SLinus Torvalds void os_kill_ptraced_process(int pid, int reap_child)
1161da177e4SLinus Torvalds {
1171da177e4SLinus Torvalds kill(pid, SIGKILL);
1181da177e4SLinus Torvalds ptrace(PTRACE_KILL, pid);
1191da177e4SLinus Torvalds ptrace(PTRACE_CONT, pid);
1201da177e4SLinus Torvalds if (reap_child)
1214dbed85aSStanislaw Gruszka CATCH_EINTR(waitpid(pid, NULL, __WALL));
1221da177e4SLinus Torvalds }
1231da177e4SLinus Torvalds
1241da177e4SLinus Torvalds /* Don't use the glibc version, which caches the result in TLS. It misses some
12560d339f6SGennady Sharapov * syscalls, and also breaks with clone(), which does not unshare the TLS.
12660d339f6SGennady Sharapov */
12760d339f6SGennady Sharapov
os_getpid(void)1281da177e4SLinus Torvalds int os_getpid(void)
1291da177e4SLinus Torvalds {
130ef0470c0SJeff Dike return syscall(__NR_getpid);
1311da177e4SLinus Torvalds }
1321da177e4SLinus Torvalds
os_getpgrp(void)133cd2ee4a3SJeff Dike int os_getpgrp(void)
134cd2ee4a3SJeff Dike {
135cd2ee4a3SJeff Dike return getpgrp();
136cd2ee4a3SJeff Dike }
137cd2ee4a3SJeff Dike
os_map_memory(void * virt,int fd,unsigned long long off,unsigned long len,int r,int w,int x)1381da177e4SLinus Torvalds int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len,
1391da177e4SLinus Torvalds int r, int w, int x)
1401da177e4SLinus Torvalds {
1411da177e4SLinus Torvalds void *loc;
1421da177e4SLinus Torvalds int prot;
1431da177e4SLinus Torvalds
1441da177e4SLinus Torvalds prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
1451da177e4SLinus Torvalds (x ? PROT_EXEC : 0);
1461da177e4SLinus Torvalds
1471da177e4SLinus Torvalds loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
1481da177e4SLinus Torvalds fd, off);
1491da177e4SLinus Torvalds if (loc == MAP_FAILED)
150ef0470c0SJeff Dike return -errno;
151ef0470c0SJeff Dike return 0;
1521da177e4SLinus Torvalds }
1531da177e4SLinus Torvalds
os_protect_memory(void * addr,unsigned long len,int r,int w,int x)1541da177e4SLinus Torvalds int os_protect_memory(void *addr, unsigned long len, int r, int w, int x)
1551da177e4SLinus Torvalds {
1561da177e4SLinus Torvalds int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
1571da177e4SLinus Torvalds (x ? PROT_EXEC : 0));
1581da177e4SLinus Torvalds
1591da177e4SLinus Torvalds if (mprotect(addr, len, prot) < 0)
160ef0470c0SJeff Dike return -errno;
161ba180fd4SJeff Dike
162ef0470c0SJeff Dike return 0;
1631da177e4SLinus Torvalds }
1641da177e4SLinus Torvalds
os_unmap_memory(void * addr,int len)1651da177e4SLinus Torvalds int os_unmap_memory(void *addr, int len)
1661da177e4SLinus Torvalds {
1671da177e4SLinus Torvalds int err;
1681da177e4SLinus Torvalds
1691da177e4SLinus Torvalds err = munmap(addr, len);
1701da177e4SLinus Torvalds if (err < 0)
171ef0470c0SJeff Dike return -errno;
172ef0470c0SJeff Dike return 0;
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds
17502dea087SJeff Dike #ifndef MADV_REMOVE
176b73781c8SJeff Dike #define MADV_REMOVE KERNEL_MADV_REMOVE
17702dea087SJeff Dike #endif
17802dea087SJeff Dike
os_drop_memory(void * addr,int length)17997a1fcbbSJeff Dike int os_drop_memory(void *addr, int length)
18002dea087SJeff Dike {
18102dea087SJeff Dike int err;
18202dea087SJeff Dike
18302dea087SJeff Dike err = madvise(addr, length, MADV_REMOVE);
18402dea087SJeff Dike if (err < 0)
18502dea087SJeff Dike err = -errno;
18602dea087SJeff Dike return err;
18702dea087SJeff Dike }
18802dea087SJeff Dike
can_drop_memory(void)18936e45463SJeff Dike int __init can_drop_memory(void)
19002dea087SJeff Dike {
19102dea087SJeff Dike void *addr;
192e3104f50SJeff Dike int fd, ok = 0;
19302dea087SJeff Dike
194ba180fd4SJeff Dike printk(UM_KERN_INFO "Checking host MADV_REMOVE support...");
19502dea087SJeff Dike fd = create_mem_file(UM_KERN_PAGE_SIZE);
19602dea087SJeff Dike if (fd < 0) {
197ba180fd4SJeff Dike printk(UM_KERN_ERR "Creating test memory file failed, "
198ba180fd4SJeff Dike "err = %d\n", -fd);
199e3104f50SJeff Dike goto out;
20002dea087SJeff Dike }
20102dea087SJeff Dike
20202dea087SJeff Dike addr = mmap64(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
203b73781c8SJeff Dike MAP_SHARED, fd, 0);
20402dea087SJeff Dike if (addr == MAP_FAILED) {
205ba180fd4SJeff Dike printk(UM_KERN_ERR "Mapping test memory file failed, "
206ba180fd4SJeff Dike "err = %d\n", -errno);
207e3104f50SJeff Dike goto out_close;
20802dea087SJeff Dike }
20902dea087SJeff Dike
21002dea087SJeff Dike if (madvise(addr, UM_KERN_PAGE_SIZE, MADV_REMOVE) != 0) {
211ba180fd4SJeff Dike printk(UM_KERN_ERR "MADV_REMOVE failed, err = %d\n", -errno);
212e3104f50SJeff Dike goto out_unmap;
21302dea087SJeff Dike }
21402dea087SJeff Dike
2155134d8feSJeff Dike printk(UM_KERN_CONT "OK\n");
216e3104f50SJeff Dike ok = 1;
217e3104f50SJeff Dike
218e3104f50SJeff Dike out_unmap:
219e3104f50SJeff Dike munmap(addr, UM_KERN_PAGE_SIZE);
220e3104f50SJeff Dike out_close:
221e3104f50SJeff Dike close(fd);
222e3104f50SJeff Dike out:
223e3104f50SJeff Dike return ok;
22402dea087SJeff Dike }
22502dea087SJeff Dike
os_page_mincore(void * addr)226f75b1b1bSRichard Weinberger static int os_page_mincore(void *addr)
227f75b1b1bSRichard Weinberger {
228f75b1b1bSRichard Weinberger char vec[2];
229f75b1b1bSRichard Weinberger int ret;
230f75b1b1bSRichard Weinberger
231f75b1b1bSRichard Weinberger ret = mincore(addr, UM_KERN_PAGE_SIZE, vec);
232f75b1b1bSRichard Weinberger if (ret < 0) {
233f75b1b1bSRichard Weinberger if (errno == ENOMEM || errno == EINVAL)
234f75b1b1bSRichard Weinberger return 0;
235f75b1b1bSRichard Weinberger else
236f75b1b1bSRichard Weinberger return -errno;
237f75b1b1bSRichard Weinberger }
238f75b1b1bSRichard Weinberger
239f75b1b1bSRichard Weinberger return vec[0] & 1;
240f75b1b1bSRichard Weinberger }
241f75b1b1bSRichard Weinberger
os_mincore(void * addr,unsigned long len)242f75b1b1bSRichard Weinberger int os_mincore(void *addr, unsigned long len)
243f75b1b1bSRichard Weinberger {
244f75b1b1bSRichard Weinberger char *vec;
245f75b1b1bSRichard Weinberger int ret, i;
246f75b1b1bSRichard Weinberger
247f75b1b1bSRichard Weinberger if (len <= UM_KERN_PAGE_SIZE)
248f75b1b1bSRichard Weinberger return os_page_mincore(addr);
249f75b1b1bSRichard Weinberger
250f75b1b1bSRichard Weinberger vec = calloc(1, (len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE);
251f75b1b1bSRichard Weinberger if (!vec)
252f75b1b1bSRichard Weinberger return -ENOMEM;
253f75b1b1bSRichard Weinberger
254f75b1b1bSRichard Weinberger ret = mincore(addr, UM_KERN_PAGE_SIZE, vec);
255f75b1b1bSRichard Weinberger if (ret < 0) {
256f75b1b1bSRichard Weinberger if (errno == ENOMEM || errno == EINVAL)
257f75b1b1bSRichard Weinberger ret = 0;
258f75b1b1bSRichard Weinberger else
259f75b1b1bSRichard Weinberger ret = -errno;
260f75b1b1bSRichard Weinberger
261f75b1b1bSRichard Weinberger goto out;
262f75b1b1bSRichard Weinberger }
263f75b1b1bSRichard Weinberger
264f75b1b1bSRichard Weinberger for (i = 0; i < ((len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); i++) {
265f75b1b1bSRichard Weinberger if (!(vec[i] & 1)) {
266f75b1b1bSRichard Weinberger ret = 0;
267f75b1b1bSRichard Weinberger goto out;
268f75b1b1bSRichard Weinberger }
269f75b1b1bSRichard Weinberger }
270f75b1b1bSRichard Weinberger
271f75b1b1bSRichard Weinberger ret = 1;
272f75b1b1bSRichard Weinberger out:
273f75b1b1bSRichard Weinberger free(vec);
274f75b1b1bSRichard Weinberger return ret;
275f75b1b1bSRichard Weinberger }
276f75b1b1bSRichard Weinberger
init_new_thread_signals(void)277e64bd134SJeff Dike void init_new_thread_signals(void)
27860d339f6SGennady Sharapov {
27900361683SAl Viro set_handler(SIGSEGV);
28000361683SAl Viro set_handler(SIGTRAP);
28100361683SAl Viro set_handler(SIGFPE);
28200361683SAl Viro set_handler(SIGILL);
28300361683SAl Viro set_handler(SIGBUS);
28460d339f6SGennady Sharapov signal(SIGHUP, SIG_IGN);
28500361683SAl Viro set_handler(SIGIO);
2863a24ebf0SJeff Dike signal(SIGWINCH, SIG_IGN);
28760d339f6SGennady Sharapov }
288