[PATCH] Try to use PTRACE_SETOPTIONS to handle non-ptrace SIGTRAP
Andreas Schwab
schwab at redhat.com
Tue Jul 20 13:29:46 UTC 2010
* 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, schwab at redhat.com
GPG Key fingerprint = D4E8 DBE3 3813 BB5D FA84 5EC7 45C6 250E 6F00 984E
"And now for something completely different."
More information about the Strace-devel
mailing list