void TraceThread::attach() { bool tasks_changed = true; ProcessTree::autopin_tid_list no_trace; int errsave, status; context.debug("TraceThread is attaching"); // attach to all tasks and child processes of the observed_process while (tasks_changed) { ProcessTree::autopin_tid_list attach_tasks = observed_process->getProcessTree().getAllTasks(); tasks_changed = false; for (const auto &attach_task : attach_tasks) { if (tasks.find(attach_task) != tasks.end()) continue; else if (no_trace.find(attach_task) != no_trace.end()) continue; else tasks_changed = true; long ret; pid_t pid = attach_task; ret = ptrace(PTRACE_ATTACH, pid, nullptr, nullptr); if (ret == -1) { errsave = errno; if (errsave == ESRCH || errsave == EPERM) { no_trace.insert(pid); context.report(Error::PROC_TRACE, "cannot_trace", "Not going to trace " + QString::number(pid)); } else { context.report(Error::UNKNOWN, "PTRACE_ATTACH", "Could not attach to process with pid " + QString::number(pid)); } continue; } // wait for the process to stop waitpid(pid, &status, __WALL); if (WIFEXITED(status)) { context.report(Error::PROC_TRACE, "cannot_trace", "Task " + QString::number(pid) + " has already exited"); continue; } // set ptrace options ret = ptrace(PTRACE_SETOPTIONS, pid, nullptr, ptrace_opt); if (ret == -1) { errsave = errno; if (errsave == ESRCH || errsave == EPERM) { no_trace.insert(pid); context.report(Error::PROC_TRACE, "cannot_trace", "Not going to trace " + QString::number(pid)); } else { context.report(Error::UNKNOWN, "PTRACE_SETOPTIONS", "Could set ptrace options for process " + QString::number(pid)); } ptrace(PTRACE_DETACH, pid, nullptr, nullptr); continue; } else { context.info(" :: Attached to task " + QString::number(pid)); tasks.insert(pid); } } } // continue all tasks for (const auto &elem : tasks) ptraceContinue(elem); // continue the process if it has been started by autopin+ if (observed_process->getExec()) kill(pid, SIGUSR1); }
/* int WaitXX(int mode,int *sigp) */ int WaitXXX(int mode,int *sigp,int *statp) { int status[4]; /**/ int pid,xpid,sig,xcode,st; int serrno; if( sigp ) *sigp = 0; for(;;) { pid = wait3(status,mode,NULL); if( statp ) { *statp = getWaitExitCode(status); } if( !lTRACE() ) if( sigp == NULL ) break; if( pid <= 0 ) break; st = status[0]; if( 0 <= (xcode = getWaitExitCode(status)) ) { if( isWindows() ) { /* introduced in 6.0.4 for PTRACE ? * but seems useless to wait exited process * and anyway unsupported on Windows */ xpid = -1; } else xpid = waitpid(pid,status,0); if( lTRVERB() ) TraceLog("- Wait [%04X] pid=%d EXITED(%d) %d\n", st,pid,xcode,xpid); return pid; } if( 0 < (sig = getWaitExitSig(status)) ) { xpid = waitpid(pid,status,0); TraceLog("- Wait [%04X] pid=%d SIGNALED(%d=%s)%s %d\n", st,pid,sig,sigsym(sig), getWaitExitCore(status)?" COREDUMP":"",xpid); if( sigp ) *sigp = sig; return pid; } if( 0 < (sig = getWaitStopSig(status)) ) { if( lTRVERB() || !usualsig(sig) ) TraceLog("- Wait [%04X] pid=%d STOPSIG(%d=%s)\n", st,pid,sig,sigsym(sig)); if( sig == SIGTRAP ) { if( lNOEXEC() ) ptraceKill(pid); else ptraceContinue(pid,0); } else ptraceContinue(pid,sig); continue; } TraceLog("- Wait [%04X] pid=%d wait unknown\n",st,pid); if( mode == WAIT_WNOHANG ) break; } /* serrno = errno; syslog_ERROR("-- Wait()=%d, errno=%d\n",pid,errno); errno = serrno; */ return pid; }
void TraceThread::run() { int status; long ret; pid_t trace_pid; unsigned long event_msg; setupSignalHandler(); // attach to processes attach(); // Check if the observed process is traced if (tasks.find(pid) == tasks.end()) { trace_mutex.unlock(); context.report(Error::PROC_TRACE, "observed_process", "Cannot trace the observed_process"); } context.info("Attached to all tasks of process " + QString::number(pid)); trace_mutex.unlock(); // start the loop for tracking process events while (true) { context.debug("Trace Thread is waiting"); // set alarm alarm(3); trace_pid = waitpid(-1, &status, __WALL); alarm(0); if (alarm_occured) { context.debug("ALARM!"); alarm_occured = false; if (exreq) break; else if (trace_pid == -1) continue; } if (trace_pid == -1) { context.report(Error::PROC_TRACE, "waitpid", "waitpid failed while tracing the observed process"); continue; } context.debug("Got signal from: " + QString::number(trace_pid)); // check return status of waitpid if (WIFEXITED(status) || WIFSIGNALED(status)) { tasks.erase(trace_pid); emit sig_TaskTerminated(trace_pid); if (pid == trace_pid) return; } else if (WIFSTOPPED(status)) { if (WSTOPSIG(status) == SIGTRAP) { ret = ptrace(PTRACE_GETEVENTMSG, trace_pid, nullptr, (void *)&event_msg); if (ret != 0) context.report(Error::PROC_TRACE, "ptrace_eventmsg", "Could not get ptrace event information"); switch (status >> 16) { case (PTRACE_EVENT_CLONE): case (PTRACE_EVENT_FORK): case (PTRACE_EVENT_VFORK): newTask(event_msg); break; default: context.debug("Received unhandled ptrace event!"); break; } ptraceContinue(trace_pid); } else if (WSTOPSIG(status) == SIGSTOP) { context.debug("Received stop signal!"); if (tasks.find(trace_pid) != tasks.end()) { ptraceContinue(trace_pid); } else newTask(trace_pid); } else { context.debug("Received unhandled signal!"); ptraceContinue(trace_pid, WSTOPSIG(status)); } } else {