[PATCH] Try to use PTRACE_SETOPTIONS to handle non-ptrace SIGTRAP

Andreas Schwab schwab at redhat.com
Wed Feb 24 12:44:38 UTC 2010


* defs.h (use_ptrace_setoptions): Declare.
* strace.c (set_ptrace_options): Define.
(is_ptrace_stop): Define.
(is_post_execve_trap): Define.
(trace): Use them.
* process.c (internal_exec): Don't set TCB_WAITEXECVE if
PTRACE_SETOPTIONS works.
---
 defs.h    |   16 +++++++++++++
 process.c |    5 ++++
 strace.c  |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 92 insertions(+), 1 deletions(-)

diff --git a/defs.h b/defs.h
index 4797e96..c0d2dcc 100644
--- a/defs.h
+++ b/defs.h
@@ -246,6 +246,22 @@ extern int ptrace(int, int, char *, int, ...);
 #define PERSONALITY1_WORDSIZE 4
 #endif
 
+#if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_SETOPTIONS)
+# define USE_PTRACE_SETOPTIONS
+# 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
+extern int use_ptrace_setoptions;
+#else
+# define use_ptrace_setoptions 0
+#endif
+
 #ifdef SVR4
 #ifdef HAVE_MP_PROCFS
 extern int mp_ioctl (int f, int c, void *a, int s);
diff --git a/process.c b/process.c
index c69e45e..eb464e2 100644
--- a/process.c
+++ b/process.c
@@ -1732,6 +1732,11 @@ struct tcb *tcp;
 		fixvfork(tcp);
 #endif /* SUNOS4 */
 #if defined LINUX && defined TCB_WAITEXECVE
+#ifdef USE_PTRACE_SETOPTIONS
+	/* Don't set TCB_WAITEXECVE when PTRACE_SETOPTIONS works. */
+	if (use_ptrace_setoptions > 0)
+		return 0;
+#endif
 	if (exiting(tcp) && syserror(tcp))
 		tcp->flags &= ~TCB_WAITEXECVE;
 	else
diff --git a/strace.c b/strace.c
index 2fb75c9..bb29729 100644
--- a/strace.c
+++ b/strace.c
@@ -2253,6 +2253,72 @@ handle_group_exit(struct tcb *tcp, int sig)
 }
 #endif
 
+#ifdef USE_PTRACE_SETOPTIONS
+int use_ptrace_setoptions = -1;
+
+static void
+set_ptrace_options(struct tcb *tcp)
+{
+	/*
+	 * Ask kernel to set signo to SIGTRAP | 0x80
+	 * on ptrace-generated SIGTRAPs, and mark
+	 * execve's SIGTRAP with PTRACE_EVENT_EXEC.
+	 */
+	if (use_ptrace_setoptions)
+		if (ptrace(PTRACE_SETOPTIONS, tcp->pid, (char *) 0,
+			   (PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC)) < 0)
+			use_ptrace_setoptions = 0;
+}
+
+static int
+is_ptrace_stop(struct tcb *tcp, int status)
+{
+	if (!use_ptrace_setoptions)
+		return WSTOPSIG(status) == SIGTRAP;
+	if (use_ptrace_setoptions > 0)
+		return (WSTOPSIG(status) == (SIGTRAP | 0x80) ||
+			((unsigned)status >> 16) == PTRACE_EVENT_EXEC);
+
+	/* Check whether PTRACE_SETOPTIONS works. */
+	if (WSTOPSIG(status) == (SIGTRAP | 0x80)) {
+		/* PTRACE_O_TRACESYSGOOD works. */
+		use_ptrace_setoptions = 1;
+		return 1;
+	}
+	if (WSTOPSIG(status) == SIGTRAP) {
+		siginfo_t si;
+
+		/* Check for post-execve trap.  */
+		if (((unsigned)status >> 16) == PTRACE_EVENT_EXEC) {
+			/* PTRACE_O_TRACEEXEC works.  */
+			use_ptrace_setoptions = 1;
+			return 1;
+		}
+		if (ptrace(PTRACE_GETSIGINFO, tcp->pid, (void *)0,
+			   (long)&si) == 0 &&
+		    (tprintf("[si_signo = %d, si_code = %d]\n",
+			     si.si_signo, si.si_code),
+		    (si.si_signo != SIGTRAP ||
+		     (si.si_code != SI_KERNEL && si.si_code != SI_USER))))
+			/* PTRACE_O_TRACEEXEC does not work.  */
+			use_ptrace_setoptions = 0;
+		return 1;
+	}
+	return 0;
+}
+
+static int
+is_post_execve_trap(struct tcb *tcp, int status)
+{
+	return (use_ptrace_setoptions && WSTOPSIG(status) == SIGTRAP &&
+		((unsigned)status >> 16) == PTRACE_EVENT_EXEC);
+}
+#else
+#define set_ptrace_options(tcp)
+#define is_ptrace_stop(tcp, status) (WSTOPSIG(status) == SIGTRAP)
+#define is_post_execve_trap(tcp, status) 0
+#endif
+
 static int
 trace()
 {
@@ -2465,10 +2531,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)) {
 				/*
@@ -2530,6 +2597,9 @@ Process %d attached (waiting for parent)\n",
 			tcp->flags &= ~TCB_SUSPENDED;
 			continue;
 		}
+		/* Ignore post-execve trap. */
+		if (is_post_execve_trap(tcp, status))
+			goto tracing;
 		/* we handled the STATUS, we are permitted to interrupt now. */
 		if (interrupted)
 			return 0;
-- 
1.7.0


-- 
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