[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