1 |
commit: 13b45f7910d6039e3a3a0971c786a5750f80cd9b |
2 |
Author: Mike Frysinger <vapier <AT> gentoo <DOT> org> |
3 |
AuthorDate: Sun Dec 20 00:55:14 2015 +0000 |
4 |
Commit: Mike Frysinger <vapier <AT> gentoo <DOT> org> |
5 |
CommitDate: Sun Dec 20 00:55:14 2015 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/sandbox.git/commit/?id=13b45f79 |
7 |
|
8 |
libsandbox: switch to PTRACE_O_TRACEEXEC |
9 |
|
10 |
Rather than try to deal with the inconsistent cross-arch behavior when it |
11 |
comes to tracking exec behavior, use the PTRACE_O_TRACEEXEC option. This |
12 |
means we only support ptrace on linux-2.6+ systems, but that's fine as we |
13 |
have been requiring that for a long time now. It also means the code is |
14 |
much simpler and stable across arches. |
15 |
|
16 |
Signed-off-by: Mike Frysinger <vapier <AT> gentoo.org> |
17 |
|
18 |
libsandbox/trace.c | 68 +++++++++++++++---------------------------- |
19 |
libsandbox/trace/linux/arch.c | 8 +++-- |
20 |
2 files changed, 29 insertions(+), 47 deletions(-) |
21 |
|
22 |
diff --git a/libsandbox/trace.c b/libsandbox/trace.c |
23 |
index f9194fe..d424389 100644 |
24 |
--- a/libsandbox/trace.c |
25 |
+++ b/libsandbox/trace.c |
26 |
@@ -430,41 +430,34 @@ static bool trace_check_syscall(const struct syscall_entry *se, void *regs) |
27 |
static void trace_loop(void) |
28 |
{ |
29 |
trace_regs regs; |
30 |
- bool before_syscall, fake_syscall_ret; |
31 |
+ bool before_exec, before_syscall, fake_syscall_ret; |
32 |
long ret; |
33 |
- int nr, exec_state; |
34 |
- const struct syscall_entry *se, *tbl_at_fork, *tbl_after_fork; |
35 |
+ int nr, status; |
36 |
+ const struct syscall_entry *se, *tbl_after_fork; |
37 |
|
38 |
- exec_state = 0; |
39 |
- before_syscall = true; |
40 |
+ before_exec = true; |
41 |
+ before_syscall = false; |
42 |
fake_syscall_ret = false; |
43 |
- tbl_at_fork = tbl_after_fork = NULL; |
44 |
+ tbl_after_fork = NULL; |
45 |
do { |
46 |
ret = do_ptrace(PTRACE_SYSCALL, NULL, NULL); |
47 |
- waitpid(trace_pid, NULL, 0); |
48 |
- ret = trace_get_regs(®s); |
49 |
- nr = trace_get_sysnum(®s); |
50 |
+ waitpid(trace_pid, &status, 0); |
51 |
|
52 |
- if (!exec_state) { |
53 |
- if (!tbl_at_fork) |
54 |
- tbl_at_fork = trace_check_personality(®s); |
55 |
- se = lookup_syscall_in_tbl(tbl_at_fork, nr); |
56 |
- if (!before_syscall || !se || se->sys != SB_NR_EXECVE) { |
57 |
- if (before_syscall) |
58 |
- _sb_debug(">%s:%i", se ? se->name : "IDK", nr); |
59 |
- else |
60 |
- __sb_debug("(...pre-exec...) = ...\n"); |
61 |
- goto loop_again; |
62 |
- } |
63 |
- ++exec_state; |
64 |
- } else if (exec_state == 1) { |
65 |
- /* Don't bother poking exec return */ |
66 |
- ++exec_state; |
67 |
- goto loop_again; |
68 |
+ if (before_exec) { |
69 |
+ unsigned event = ((unsigned)status >> 16); |
70 |
+ if (event == PTRACE_EVENT_EXEC) { |
71 |
+ _sb_debug("hit exec!"); |
72 |
+ before_exec = false; |
73 |
+ } else |
74 |
+ _sb_debug("waiting for exec; status: %#x", status); |
75 |
+ ret = trace_get_regs(®s); |
76 |
+ tbl_after_fork = trace_check_personality(®s); |
77 |
+ continue; |
78 |
} |
79 |
|
80 |
- if (!tbl_after_fork) |
81 |
- tbl_after_fork = trace_check_personality(®s); |
82 |
+ ret = trace_get_regs(®s); |
83 |
+ nr = trace_get_sysnum(®s); |
84 |
+ |
85 |
se = lookup_syscall_in_tbl(tbl_after_fork, nr); |
86 |
ret = trace_get_regs(®s); |
87 |
if (before_syscall) { |
88 |
@@ -486,24 +479,11 @@ static void trace_loop(void) |
89 |
ret = trace_result(®s, &err); |
90 |
|
91 |
__sb_debug(" = %li", ret); |
92 |
- if (err) { |
93 |
+ if (err) |
94 |
__sb_debug(" (errno: %i: %s)", err, strerror(err)); |
95 |
- |
96 |
- /* If the exec() failed for whatever reason, kill the |
97 |
- * child and have the parent resume like normal |
98 |
- */ |
99 |
- if (exec_state == 1) { |
100 |
- do_ptrace(PTRACE_KILL, NULL, NULL); |
101 |
- trace_pid = 0; |
102 |
- return; |
103 |
- } |
104 |
- } |
105 |
__sb_debug("\n"); |
106 |
- |
107 |
- exec_state = 2; |
108 |
} |
109 |
|
110 |
- loop_again: |
111 |
before_syscall = !before_syscall; |
112 |
} while (1); |
113 |
} |
114 |
@@ -527,10 +507,8 @@ void trace_main(const char *filename, char *const argv[]) |
115 |
} else if (trace_pid) { |
116 |
sb_debug("parent waiting for child (pid=%i) to signal", trace_pid); |
117 |
waitpid(trace_pid, NULL, 0); |
118 |
-#if defined(PTRACE_SETOPTIONS) && defined(PTRACE_O_TRACESYSGOOD) |
119 |
- /* Not all kernel versions support this, so ignore return */ |
120 |
- ptrace(PTRACE_SETOPTIONS, trace_pid, NULL, (void *)PTRACE_O_TRACESYSGOOD); |
121 |
-#endif |
122 |
+ do_ptrace(PTRACE_SETOPTIONS, NULL, |
123 |
+ (void *)(PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC)); |
124 |
sb_close_all_fds(); |
125 |
trace_loop(); |
126 |
sb_ebort("ISE: child should have quit, as should we\n"); |
127 |
|
128 |
diff --git a/libsandbox/trace/linux/arch.c b/libsandbox/trace/linux/arch.c |
129 |
index 5ca1acb..957db3b 100644 |
130 |
--- a/libsandbox/trace/linux/arch.c |
131 |
+++ b/libsandbox/trace/linux/arch.c |
132 |
@@ -1,7 +1,11 @@ |
133 |
#include "common.c" |
134 |
|
135 |
-/* Linux uses ptrace() */ |
136 |
-#if !defined(HAVE_PTRACE) || !defined(HAVE_SYS_PTRACE_H) || !defined(HAVE_SYS_USER_H) |
137 |
+/* Linux uses ptrace(). We require PTRACE_SETOPTIONS so the exec tracing logic |
138 |
+ * is sane. Otherwise we need a lot of arch-specific hacks to make it work. |
139 |
+ * This should be fine for linux-2.6+ versions. |
140 |
+ */ |
141 |
+#if !defined(HAVE_PTRACE) || !defined(HAVE_SYS_PTRACE_H) || \ |
142 |
+ !defined(HAVE_SYS_USER_H) || !defined(PTRACE_SETOPTIONS) |
143 |
# define SB_NO_TRACE_ARCH |
144 |
#elif defined(__bfin__) |
145 |
# include "bfin.c" |