[PATCH] Try to use PTRACE_SETOPTIONS to handle non-ptrace SIGTRAP
Andreas Schwab
schwab at redhat.com
Thu Mar 4 14:17:47 UTC 2010
* defs.h (TCB_PTRACE_OPTIONS) [LINUX && PTRACE_SETOPTIONS]:
Define.
* process.c (internal_fork): Copy TCB_PTRACE_OPTIONS flag to
child.
(internal_exec): Only set TCB_WAITEXECVE on entering.
* strace.c (set_ptrace_options, is_ptrace_stop)
(is_post_execve_trap): Define.
(proc_open): Use them.
---
defs.h | 12 +++++++++
process.c | 10 +++++--
strace.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 97 insertions(+), 4 deletions(-)
diff --git a/defs.h b/defs.h
index 4797e96..9001a85 100644
--- a/defs.h
+++ b/defs.h
@@ -378,6 +378,18 @@ struct tcb {
# define TCB_CLONE_DETACHED 04000 /* CLONE_DETACHED set in creating syscall */
# define TCB_CLONE_THREAD 010000 /* CLONE_THREAD set in creating syscall */
# define TCB_GROUP_EXITING 020000 /* TCB_EXITING was exit_group, not _exit */
+# if defined LINUX && (defined PTRACE_SETOPTIONS || defined PT_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
+# define TCB_PTRACE_OPTIONS 040000 /* PTRACE_SETOPTIONS called */
+# endif
# include <sys/syscall.h>
# ifndef __NR_exit_group
# /* Hack: Most headers around are too old to have __NR_exit_group. */
diff --git a/process.c b/process.c
index c69e45e..cc02921 100644
--- a/process.c
+++ b/process.c
@@ -866,6 +866,9 @@ internal_fork(struct tcb *tcp)
clearbpt(tcpchild);
tcpchild->flags &= ~(TCB_SUSPENDED|TCB_STARTUP);
+#ifdef TCB_PTRACE_OPTIONS
+ tcpchild->flags |= tcp->flags & TCB_PTRACE_OPTIONS;
+#endif
if (ptrace_restart(PTRACE_SYSCALL, tcpchild, 0) < 0)
return -1;
@@ -1732,9 +1735,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 2fb75c9..701d366 100644
--- a/strace.c
+++ b/strace.c
@@ -2253,6 +2253,75 @@ handle_group_exit(struct tcb *tcp, int sig)
}
#endif
+#ifdef TCB_PTRACE_OPTIONS
+
+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)
+ tcp->flags |= TCB_PTRACE_OPTIONS;
+ else if (errno != ESRCH)
+ use_ptrace_setoptions = 0;
+}
+
+static int
+is_ptrace_stop(struct tcb *tcp, int status)
+{
+ if (!(tcp->flags & TCB_PTRACE_OPTIONS))
+ 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 must be the post-execve trap. */
+ if ((tcp->flags & (TCB_STARTUP|TCB_ATTACHED|TCB_PTRACE_OPTIONS)) ==
+ (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
+
static int
trace()
{
@@ -2465,10 +2534,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)) {
/*
@@ -2533,6 +2603,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.0.1
Andreas.
--
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