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