diff --git a/src/kernel/emulation/linux/CMakeLists.txt b/src/kernel/emulation/linux/CMakeLists.txt index 471388283..a354277e8 100644 --- a/src/kernel/emulation/linux/CMakeLists.txt +++ b/src/kernel/emulation/linux/CMakeLists.txt @@ -131,6 +131,7 @@ set(emulation_sources signal/sigprocmask.c signal/sig_restorer.S signal/sigsuspend.c + misc/ptrace.c misc/getentropy.c misc/syscall.c misc/shared_region_check_np.c diff --git a/src/kernel/emulation/linux/misc/ptrace.c b/src/kernel/emulation/linux/misc/ptrace.c new file mode 100644 index 000000000..0e34923c4 --- /dev/null +++ b/src/kernel/emulation/linux/misc/ptrace.c @@ -0,0 +1,88 @@ +#include "ptrace.h" +#include "../base.h" +#include "../simple.h" +#include "../errno.h" +#include +#include +#include +#include +#include "../signal/kill.h" +#include "../signal/duct_signals.h" + +#define LINUX_PTRACE_TRACEME 0 +#define LINUX_PTRACE_ATTACH 16 +#define LINUX_PTRACE_DETACH 17 +#define LINUX_PTRACE_CONT 7 + +long sys_ptrace(int request, int pid, void* addr, int data) +{ + const char* cmd = NULL; + + switch (request) + { + case PT_PTRACE_ME: + { + int ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_TRACEME, pid, addr, data); + + if (ret < 0) + ret = errno_linux_to_bsd(ret); + + return ret; + //cmd = "PT_PTRACE_ME"; break; + } + case PT_KILL: + return sys_kill(pid, SIGKILL, 1); + // cmd = "PT_KILL"; break; + case PT_ATTACH: // PT_ATTACH + case PT_ATTACHEXC: // PT_ATTACHEXC + { + //do_attach: + int ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_ATTACH, pid, addr, data); + + if (ret < 0) + ret = errno_linux_to_bsd(ret); + + return ret; + // cmd = "PT_ATTACH"; break; + } + case PT_DETACH: + { + int ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_DETACH, pid, addr, data); + + if (ret < 0) + ret = errno_linux_to_bsd(ret); + + return ret; + // cmd = "PT_DETACH"; break; + } + case PT_SIGEXC: + cmd = "PT_SIGEXC"; break; + case PT_CONTINUE: + // case PT_THUPDATE: + { + int signal = 0; + if (data != -1) + signal = signum_bsd_to_linux(data); + int ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_CONT, pid, NULL, signal); + + if (ret < 0) + ret = errno_linux_to_bsd(ret); + + return ret; + // cmd = "PT_THUPDATE"; break; + } + //case 14: + //{ + // goto do_attach; + // cmd = "PT_ATTACHEXC"; break; + //} + } + + if (cmd != NULL) + __simple_printf("ptrace() req=%s\n", cmd); + else + __simple_printf("ptrace() req=%d\n", request); + + return -ENOSYS; +} + diff --git a/src/kernel/emulation/linux/misc/ptrace.h b/src/kernel/emulation/linux/misc/ptrace.h new file mode 100644 index 000000000..85205de07 --- /dev/null +++ b/src/kernel/emulation/linux/misc/ptrace.h @@ -0,0 +1,16 @@ +#ifndef LINUX_PTRACE_H +#define LINUX_PTRACE_H + +#define PT_PTRACE_ME 0 +#define PT_CONTINUE 7 +#define PT_KILL 8 +#define PT_ATTACH 10 +#define PT_ATTACHEXC 14 +#define PT_DETACH 11 +#define PT_SIGEXC 12 +#define PT_THUPDATE 13 + +long sys_ptrace(int request, int pid, void* addr, int data); + +#endif + diff --git a/src/kernel/emulation/linux/process/wait4.c b/src/kernel/emulation/linux/process/wait4.c index 4fa09bdbc..89ba6d06d 100644 --- a/src/kernel/emulation/linux/process/wait4.c +++ b/src/kernel/emulation/linux/process/wait4.c @@ -2,19 +2,28 @@ #include "../base.h" #include "../errno.h" #include "../signal/duct_signals.h" +#include "../misc/ptrace.h" +#include +#include #include long sys_wait4(int pid, int* status, int options, void* rusage) { int ret, linux_options; + int mystatus; + + // We always need status even if the caller doesn't + if (status == NULL) + status = &mystatus; linux_options = waitopts_bsd_to_linux(options); +restart: ret = LINUX_SYSCALL(__NR_wait4, pid, status, linux_options, rusage); if (ret < 0) return errno_linux_to_bsd(ret); - if ((*status & 0x7f) != 0x7f) + if ((*status & 0x7f) != 0x7f) // process terminated { int signum; @@ -24,6 +33,29 @@ long sys_wait4(int pid, int* status, int options, void* rusage) } else if (*status == 0xffff) // Linux: __W_CONTINUED *status = 0x7f | (0x13 << 8); + else if ((*status & 0x7f) == 0x7f) // process stopped + { + int signal = *status >> 8; + signal = signum_linux_to_bsd(signal); + *status = (*status & 0x7f) | (signal << 8); + + switch (signal) + { + case SIGCONT: + case SIGSTOP: + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + // It is standard behavior that these signals stop (resume) the process + break; + default: + // We are probably ptracing the target process. + // Allow the execution to continue so that the ptraced process can translate + // the signal into a Mach message. + sys_ptrace(PT_CONTINUE, ret, NULL, signal); + goto restart; + } + } return ret; } diff --git a/src/kernel/emulation/linux/syscalls.c b/src/kernel/emulation/linux/syscalls.c index 9fcdf29bf..c782f9aab 100644 --- a/src/kernel/emulation/linux/syscalls.c +++ b/src/kernel/emulation/linux/syscalls.c @@ -98,6 +98,7 @@ #include "process/getpriority.h" #include "process/setpriority.h" #include "misc/getentropy.h" +#include "misc/ptrace.h" #include "misc/getlogin.h" #include "misc/setlogin.h" #include "misc/reboot.h" @@ -209,6 +210,7 @@ void* __bsd_syscall_table[600] = { [23] = sys_setuid, [24] = sys_getuid, [25] = sys_geteuid, + [26] = sys_ptrace, [27] = sys_recvmsg, [28] = sys_sendmsg, [29] = sys_recvfrom,