From 9b39d9239bfbc78d3e6817a2339dca35f4dd650a Mon Sep 17 00:00:00 2001 From: sgf Date: Wed, 22 Nov 2023 17:34:47 +0300 Subject: [PATCH] new(ptrace): Ptrace child, which ptraces its own child. --- .../guide_to_syscalls/myStrace/ptrace-chain.c | 256 ++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 containers_from_scratch/guide_to_syscalls/myStrace/ptrace-chain.c diff --git a/containers_from_scratch/guide_to_syscalls/myStrace/ptrace-chain.c b/containers_from_scratch/guide_to_syscalls/myStrace/ptrace-chain.c new file mode 100644 index 0000000..ef8d9e7 --- /dev/null +++ b/containers_from_scratch/guide_to_syscalls/myStrace/ptrace-chain.c @@ -0,0 +1,256 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// https://stackoverflow.com/questions/2359581/calling-ptrace-inside-a-ptraced-linux-process +// https://stackoverflow.com/questions/18437779/do-i-need-to-do-anything-with-a-sigchld-handler-if-i-am-just-using-wait-to-wai + +extern const char * const sys_siglist[]; + +static pid_t child_pid; + +static void a(){ + while(1){ + printf ("A\n"); + fflush(stdout); + sleep(1); + } +} + +static void b(){ + while(1){ + printf ("B\n"); + fflush(stdout); + sleep(1); + } +} + +static void c(){ + while(1){ + printf ("C\n"); + fflush(stdout); + sleep(1); + } +} + +static void child_has_stopped(pid_t cpid, int status) { + + size_t n_pref = 1 + snprintf(NULL, 0, "[Child %d]:", cpid); + char *pref = malloc(n_pref); + snprintf(pref, n_pref, "[Child %d]:", cpid); + + if (WIFEXITED(status)) { + printf("%s: Child exited with status=%d\n", pref, WEXITSTATUS(status)); + child_pid = 0; + raise(SIGINT); + + } else if (WIFSIGNALED(status)) { + int termsig = WTERMSIG(status); + printf("%s: Child killed by signal '%s' (%d)\n", pref, sys_siglist[termsig], termsig); + child_pid = 0; + raise(SIGINT); + + } else if (WIFSTOPPED(status)) { + int csig = WSTOPSIG(status); + + n_pref = 1 + snprintf(pref, n_pref, "[Child %d] (%d):", cpid, csig); + pref = realloc(pref, n_pref); + snprintf(pref, n_pref, "[Child %d] (%d):", cpid, csig); + + printf("%s: Child is traced and and is about to receive '%s' (%d)\n", pref, sys_siglist[csig], csig); + + switch (csig) { + case SIGTRAP|0x80: + printf("%s: Tracee is in syscall-stop (SYSGOOD)\n", pref); + siginfo_t csiginfo; + int ret = ptrace(PTRACE_GETSIGINFO, cpid, 0, &csiginfo); + if (csiginfo.si_signo == SIGTRAP && csiginfo.si_code == SIGTRAP|0x80) { + printf("%s: Tracee's syscall-stop confirmed (SYSGOOD)\n", pref); + } + + break; + + case SIGTRAP: + printf("%s: Tracee trapped\n", pref); + switch (status>>8) { + case ((PTRACE_EVENT_VFORK<<8) | SIGTRAP): + case ((PTRACE_EVENT_FORK<<8) | SIGTRAP): + case ((PTRACE_EVENT_CLONE<<8) | SIGTRAP): + case ((PTRACE_EVENT_VFORK_DONE<<8) | SIGTRAP): + case ((PTRACE_EVENT_EXEC<<8) | SIGTRAP): + case ((PTRACE_EVENT_EXIT<<8) | SIGTRAP): + case ((PTRACE_EVENT_STOP<<8) | SIGTRAP): + ret = ptrace(PTRACE_GETSIGINFO, cpid, 0, &csiginfo); + printf("%s: Tracee is in ptrace-event stop (si_code = %d)\n", pref, csiginfo.si_code); + break; + + default: + ret = ptrace(PTRACE_GETSIGINFO, cpid, 0, &csiginfo); + if (csiginfo.si_code <= 0) { + printf("%s: Tracee is in signal-delivery stop: received SIGTRAP from user-space\n", pref); + } else if (csiginfo.si_code == SI_KERNEL) { + printf("%s: Tracee is in signal-delivery stop: received SIGTRAP from kernel\n", pref); + } else if (csiginfo.si_code == SIGTRAP) { + printf("%s: Tracee is in syscall-stop\n", pref); + } else { + printf("%s: Tracee is in some other trap..\n", pref); + } + + break; + } + + break; + + case SIGSTOP: + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + ret = ptrace(PTRACE_GETSIGINFO, cpid, 0, &csiginfo); + if (ret == -1 && errno == EINVAL) { + printf("%s: Tracee is in group-stop, ignoring stop signal %d\n", pref, csig); + ptrace(PTRACE_CONT, cpid, 0, 0); + } else { + printf("%s: Tracee is in STOP signal signal-delivery-stop, injecting stop signal %d\n", pref, csig); + ptrace(PTRACE_CONT, cpid, 0, csig); + } + + break; + + default: + printf("%s: Tracee is in signal-delivery-stop, injecting signal %d\n", pref, csig); + ptrace(PTRACE_CONT, cpid, 0, csig); + break; + } + + } else if (WIFCONTINUED(status)) { + printf("%s: Child continued\n", pref); + + } else { + printf("%s: Child is elsewhere\n", pref); + } + + free(pref); +} + +// FIXME: Try sigaction with SA_NOCLDSTOP . +static void catcher(int sig, siginfo_t *info, void *vp) { + pid_t mypid = getpid(); + + size_t n_pref = 1 + snprintf(NULL, 0, "[%d] (%d):", mypid, sig); + char *pref = malloc(n_pref); + + snprintf(pref, n_pref, "[%d] (%d)", mypid, sig); + + printf("%s: Received signal '%s' (%d) on %d (reason %d)\n", pref, sys_siglist[sig], sig, info->si_pid, info->si_code); + + switch (sig) { + case SIGINT: + if (child_pid != 0) { + printf("%s: SIGINT: Resend to child %d\n", pref, child_pid); + kill(child_pid, SIGINT); + } else { + printf("%s: SIGINT: No child left, exit\n", pref); + _exit(123); + } + break; + + case SIGTRAP: + printf("%s: We're trapped\n", pref); + break; + + case SIGCHLD: { + // *info - info about signal received by _parent_. + switch (info->si_code) { + case CLD_EXITED: + printf("%s: SIGCHLD: Child has exited with %d\n", pref, info->si_status); + break; + case CLD_KILLED: + printf("%s: SIGCHLD: Child was killed by '%s' (%d).\n", pref, sys_siglist[info->si_status], info->si_status); + break; + case CLD_DUMPED: + printf("%s: SIGCHLD: Child terminated abnormally.\n", pref); + break; + case CLD_TRAPPED: + printf("%s: SIGCHLD: Traced child has trapped by '%s' (%d)\n", pref, sys_siglist[info->si_status], info->si_status); + break; + case CLD_STOPPED: + printf("%s: SIGCHLD: Child has stopped by '%s' (%d)\n", pref, sys_siglist[info->si_status], info->si_status); + break; + case CLD_CONTINUED: + printf("%s: SIGCHLD: Stopped child has continued by '%s' (%d).\n", pref, sys_siglist[info->si_status], info->si_status); + break; + } + + int wstatus; + pid_t child_pid; + while ((child_pid = waitpid(-1, &wstatus, WNOHANG)) > 0) { + printf("%s: Child pid %d\n", pref, child_pid); + + child_has_stopped(child_pid, wstatus); + } + } + } + printf("%s: --\n", pref); +} + +int main(int argc, + char **argv){ + + printf("pidA = %d\n", getpid()); + + struct sigaction sa; + sa.sa_sigaction = catcher; + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGTRAP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + int result; + + printf("Forking B\n"); + child_pid = fork(); + if (child_pid) { + printf("pidB = %d\n", child_pid); + + sleep(1); + printf("[%d]: attaching to B..\n", getpid()); + result = ptrace(PTRACE_ATTACH, child_pid, NULL, NULL); + if(result == -1){ + perror("outer ptrace"); + } + + a(); + + } else { + printf("B Started\n"); + sleep(3); + printf("Forking C\n"); + child_pid = fork(); + + //b(); + if (child_pid) { + printf("pidC = %d\n", child_pid); + + printf("[%d]: attaching to pidC..\n", getpid()); + result = ptrace(PTRACE_ATTACH, child_pid, NULL, NULL); + if(result==-1){ + perror("inner ptrace"); + } + + b(); + + } else { + printf("C Started\n"); + c(); + } + } + + return 0; +} -- 2.20.1