From: Andreas S. <sc...@re...> - 2010-07-20 15:12:13
|
* defs.h (USE_PTRACE_SETOPTIONS) [LINUX]: Define. * process.c (internal_exec): Only set TCB_WAITEXECVE on entering. * strace.c (set_ptrace_options, is_ptrace_stop) (is_post_execve_trap): Define. (detach, trace): Use them. --- defs.h | 16 ++++++++++++ process.c | 7 +++-- strace.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 98 insertions(+), 5 deletions(-) diff --git a/defs.h b/defs.h index 419b12e..54b1a30 100644 --- a/defs.h +++ b/defs.h @@ -308,6 +308,22 @@ extern int mp_ioctl (int f, int c, void *a, int s); #define PR_FAULTED S_CORE #endif +#if defined LINUX +# define USE_PTRACE_SETOPTIONS +# ifndef PTRACE_SETOPTIONS +# define PTRACE_SETOPTIONS 0x4200 +# endif +# ifndef PTRACE_O_TRACESYSGOOD +# define PTRACE_O_TRACESYSGOOD 0x00000001 +# endif +# ifndef PTRACE_O_TRACEEXEC +# define PTRACE_O_TRACEEXEC 0x00000010 +# endif +# ifndef PTRACE_EVENT_EXEC +# define PTRACE_EVENT_EXEC 4 +# endif +#endif + /* Trace Control Block */ struct tcb { short flags; /* See below for TCB_ values */ diff --git a/process.c b/process.c index dadf830..ff78ff0 100644 --- a/process.c +++ b/process.c @@ -1732,9 +1732,10 @@ struct tcb *tcp; fixvfork(tcp); #endif /* SUNOS4 */ #if defined LINUX && defined TCB_WAITEXECVE - if (exiting(tcp) && syserror(tcp)) - tcp->flags &= ~TCB_WAITEXECVE; - else + if (exiting(tcp)) { + if (syserror(tcp)) + tcp->flags &= ~TCB_WAITEXECVE; + } else tcp->flags |= TCB_WAITEXECVE; #endif /* LINUX && TCB_WAITEXECVE */ return 0; diff --git a/strace.c b/strace.c index 21febb3..47c6553 100644 --- a/strace.c +++ b/strace.c @@ -1367,6 +1367,74 @@ int pfd; #endif /* USE_PROCFS */ +#ifdef USE_PTRACE_SETOPTIONS + +static int use_ptrace_setoptions = 1; +static int probe_ptrace_setoptions = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC; + +static void +set_ptrace_options(struct tcb *tcp) +{ + if (!use_ptrace_setoptions) + return; + + /* + * Ask kernel to set signo to SIGTRAP | 0x80 + * on ptrace-generated SIGTRAPs, and mark + * execve's SIGTRAP with PTRACE_EVENT_EXEC. + */ + if (ptrace(PTRACE_SETOPTIONS, tcp->pid, (char *) 0, + PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC) < 0 && + errno != ESRCH) + use_ptrace_setoptions = 0; +} + +static int +is_ptrace_stop(struct tcb *tcp, int status) +{ + if (tcp->flags & TCB_STARTUP) + /* Didn't have the chance to set ptrace options yet. */ + return WSTOPSIG(status) == SIGTRAP; + + if (WSTOPSIG(status) == (SIGTRAP | 0x80)) { + /* PTRACE_O_TRACESYSGOOD works. */ + probe_ptrace_setoptions &= PTRACE_O_TRACESYSGOOD; + return 1; + } + if (WSTOPSIG(status) == SIGTRAP && + ((unsigned)status >> 16) == PTRACE_EVENT_EXEC) { + /* PTRACE_O_TRACEEXEC works. */ + probe_ptrace_setoptions &= PTRACE_O_TRACEEXEC; + return 1; + } + + if ((WSTOPSIG(status) == SIGTRAP && probe_ptrace_setoptions)) + return 1; + return 0; +} + +static int +is_post_execve_trap(struct tcb *tcp, int status) +{ + if (!use_ptrace_setoptions) + return 0; + + if (WSTOPSIG(status) == SIGTRAP) { + if (((unsigned)status >> 16) == PTRACE_EVENT_EXEC) + return 1; + /* A SIGTRAP received before the first ptrace stop + after attaching is most likely the post-execve trap. */ + if ((tcp->flags & (TCB_STARTUP|TCB_ATTACHED)) == (TCB_STARTUP|TCB_ATTACHED)) + return 1; + } + return 0; +} +#else +#define set_ptrace_options(tcp) +#define is_ptrace_stop(tcp, status) (WSTOPSIG(status) == SIGTRAP) +#define is_post_execve_trap(tcp, status) 0 +#endif + void droptcb(tcp) struct tcb *tcp; @@ -1632,7 +1700,7 @@ int sig; break; } error = ptrace_restart(PTRACE_CONT, tcp, - WSTOPSIG(status) == SIGTRAP ? 0 + is_ptrace_stop(tcp, status) ? 0 : WSTOPSIG(status)); if (error < 0) break; @@ -2482,10 +2550,11 @@ Process %d attached (waiting for parent)\n", return -1; } } + set_ptrace_options(tcp); goto tracing; } - if (WSTOPSIG(status) != SIGTRAP) { + if (!is_ptrace_stop(tcp, status)) { if (WSTOPSIG(status) == SIGSTOP && (tcp->flags & TCB_SIGTRAPPED)) { /* @@ -2550,6 +2619,13 @@ Process %d attached (waiting for parent)\n", /* we handled the STATUS, we are permitted to interrupt now. */ if (interrupted) return 0; + /* Ignore post-execve trap. */ + if (is_post_execve_trap(tcp, status)) { +#ifdef TCB_WAITEXECVE + tcp->flags &= ~TCB_WAITEXECVE; +#endif + goto tracing; + } if (trace_syscall(tcp) < 0 && !tcp->ptrace_errno) { /* ptrace() failed in trace_syscall() with ESRCH. * Likely a result of process disappearing mid-flight. -- 1.7.1.1 -- Andreas Schwab, sc...@re... GPG Key fingerprint = D4E8 DBE3 3813 BB5D FA84 5EC7 45C6 250E 6F00 984E "And now for something completely different." |