1 |
commit: 0a9188fd0a812cb864819d37a6a7217a135b85f0 |
2 |
Author: Mike Frysinger <vapier <AT> gentoo <DOT> org> |
3 |
AuthorDate: Sun Sep 20 22:25:33 2015 +0000 |
4 |
Commit: Mike Frysinger <vapier <AT> gentoo <DOT> org> |
5 |
CommitDate: Sun Sep 20 22:25:33 2015 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/sandbox.git/commit/?id=0a9188fd |
7 |
|
8 |
libsandbox: do not abort when the target uses bad pointers |
9 |
|
10 |
If the target passes a bad pointer to the kernel, then trying to extract |
11 |
the data via ptrace will also throw an error. The tracing code should not |
12 |
abort though as there's no valid address to check, and kernel itself will |
13 |
return an error for us. Simply return and move on. |
14 |
|
15 |
URL: https://bugs.gentoo.org/560396 |
16 |
Reported-by: Jeroen Roovers <jer <AT> gentoo.org> |
17 |
Signed-off-by: Mike Frysinger <vapier <AT> gentoo.org> |
18 |
|
19 |
libsandbox/trace.c | 14 ++++++++++ |
20 |
localdecls.h | 4 +++ |
21 |
tests/Makefile.am | 3 +- |
22 |
tests/script-13.sh | 5 ++++ |
23 |
tests/script.at | 1 + |
24 |
tests/tests.h | 4 +++ |
25 |
tests/trace-memory_static_tst.c | 62 +++++++++++++++++++++++++++++++++++++++++ |
26 |
7 files changed, 92 insertions(+), 1 deletion(-) |
27 |
|
28 |
diff --git a/libsandbox/trace.c b/libsandbox/trace.c |
29 |
index 99ef8cd..f9194fe 100644 |
30 |
--- a/libsandbox/trace.c |
31 |
+++ b/libsandbox/trace.c |
32 |
@@ -59,6 +59,11 @@ static long _do_ptrace(enum __ptrace_request request, const char *srequest, void |
33 |
} |
34 |
sched_yield(); |
35 |
goto try_again; |
36 |
+ } else if (errno == EIO || errno == EFAULT) { |
37 |
+ /* This comes up when the child itself tries to use a bad pointer. |
38 |
+ * That's not something the sandbox should abort on. #560396 |
39 |
+ */ |
40 |
+ return ret; |
41 |
} else if (!errno) |
42 |
if (request == PTRACE_PEEKDATA || |
43 |
request == PTRACE_PEEKTEXT || |
44 |
@@ -140,7 +145,16 @@ static char *do_peekstr(unsigned long lptr) |
45 |
while (1) { |
46 |
a = lptr & (sizeof(long) - 1); |
47 |
lptr -= a; |
48 |
+ errno = 0; |
49 |
s.val = do_peekdata(lptr); |
50 |
+ if (unlikely(errno)) { |
51 |
+ if (errno == EIO || errno == EFAULT) { |
52 |
+ ret[0] = '\0'; |
53 |
+ return ret; |
54 |
+ } |
55 |
+ sb_ebort("ISE:do_peekstr:do_peekdata(%#lx) failed: %s\n", |
56 |
+ lptr, strerror(errno)); |
57 |
+ } |
58 |
for (i = a; i < sizeof(long); ++i) { |
59 |
ret[l++] = s.x[i]; |
60 |
if (!s.x[i]) |
61 |
|
62 |
diff --git a/localdecls.h b/localdecls.h |
63 |
index 0e11fea..ecc5856 100644 |
64 |
--- a/localdecls.h |
65 |
+++ b/localdecls.h |
66 |
@@ -102,6 +102,10 @@ typedef struct user_regs_struct trace_regs; |
67 |
#ifndef offsetof |
68 |
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) |
69 |
#endif |
70 |
+#define ALIGN_DOWN(base, size) ((base) & -(size)) |
71 |
+#define ALIGN_UP(base, size) ALIGN_DOWN((base) + (size) - 1, (size)) |
72 |
+#define PTR_ALIGN_DOWN(base, size) ((__typeof__(base))ALIGN_DOWN((uintptr_t)(base), (size))) |
73 |
+#define PTR_ALIGN_UP(base, size) ((__typeof__(base))ALIGN_UP((uintptr_t)(base), (size))) |
74 |
|
75 |
/* If the system is old and does not support *at funcs, then define |
76 |
* it ourself. Shouldn't matter based on how we use it. |
77 |
|
78 |
diff --git a/tests/Makefile.am b/tests/Makefile.am |
79 |
index 0f0c249..3627344 100644 |
80 |
--- a/tests/Makefile.am |
81 |
+++ b/tests/Makefile.am |
82 |
@@ -76,7 +76,8 @@ check_PROGRAMS = \ |
83 |
pipe-fork_static_tst \ |
84 |
sb_printf_tst \ |
85 |
sigsuspend-zsh_tst \ |
86 |
- sigsuspend-zsh_static_tst |
87 |
+ sigsuspend-zsh_static_tst \ |
88 |
+ trace-memory_static_tst |
89 |
|
90 |
dist_check_SCRIPTS = \ |
91 |
$(wildcard $(srcdir)/*-[0-9]*.sh) \ |
92 |
|
93 |
diff --git a/tests/script-13.sh b/tests/script-13.sh |
94 |
new file mode 100755 |
95 |
index 0000000..24a0e3b |
96 |
--- /dev/null |
97 |
+++ b/tests/script-13.sh |
98 |
@@ -0,0 +1,5 @@ |
99 |
+#!/bin/sh |
100 |
+# make sure poking remote addresses works even when they're bad/unaligned #560396 |
101 |
+[ "${at_xfail}" = "yes" ] && exit 77 # see script-0 |
102 |
+ |
103 |
+trace-memory_static_tst |
104 |
|
105 |
diff --git a/tests/script.at b/tests/script.at |
106 |
index f07a8f1..58a5077 100644 |
107 |
--- a/tests/script.at |
108 |
+++ b/tests/script.at |
109 |
@@ -10,3 +10,4 @@ SB_CHECK(9, [wait errpipe... done OK!]) |
110 |
SB_CHECK(10) |
111 |
SB_CHECK(11) |
112 |
SB_CHECK(12) |
113 |
+SB_CHECK(13) |
114 |
|
115 |
diff --git a/tests/tests.h b/tests/tests.h |
116 |
index 72c678c..51dc68a 100644 |
117 |
--- a/tests/tests.h |
118 |
+++ b/tests/tests.h |
119 |
@@ -1,5 +1,9 @@ |
120 |
#include "headers.h" |
121 |
|
122 |
+/* Make sure assert() works in tests. */ |
123 |
+#undef NDEBUG |
124 |
+#include <assert.h> |
125 |
+ |
126 |
#define _msg(std, fmt, args...) fprintf(std, "%s:%s():%i: " fmt "\n", __FILE__, __func__, __LINE__, ##args) |
127 |
#define _stderr_msg(fmt, args...) _msg(stderr, fmt, ##args) |
128 |
#define _stderr_pmsg(fmt, args...) _msg(stderr, fmt ": %s", ##args, strerror(errno)) |
129 |
|
130 |
diff --git a/tests/trace-memory_static_tst.c b/tests/trace-memory_static_tst.c |
131 |
new file mode 100644 |
132 |
index 0000000..14c6477 |
133 |
--- /dev/null |
134 |
+++ b/tests/trace-memory_static_tst.c |
135 |
@@ -0,0 +1,62 @@ |
136 |
+/* |
137 |
+ * Make sure the process_vm_readv func can work with strings with different |
138 |
+ * alignments and lengths. |
139 |
+ * |
140 |
+ * https://bugs.gentoo.org/560396 |
141 |
+ */ |
142 |
+ |
143 |
+/* We want to make some bad calls. */ |
144 |
+#undef _FORTIFY_SOURCES |
145 |
+ |
146 |
+#include "tests.h" |
147 |
+ |
148 |
+/* Make sure the buffer spans multiple pages. */ |
149 |
+#define SIZE 0x1000 |
150 |
+/* Make sure the buffer has plenty of slack space before/after. */ |
151 |
+static char buf[SIZE * 8]; |
152 |
+ |
153 |
+/* The smaller the span, the # of calls goes up: O(N*N*2+N). */ |
154 |
+#define COUNT 0x20 |
155 |
+#define STRIDE (SIZE / COUNT) |
156 |
+ |
157 |
+/* Some hacks to defeat gcc warnings so we can use bad pointers. */ |
158 |
+volatile uintptr_t offset = 0; |
159 |
+#define non_const_ptr(ptr) ((void *)((uintptr_t)(ptr) + offset)) |
160 |
+ |
161 |
+#define check_ptr(addr) \ |
162 |
+({ \ |
163 |
+ printf(" open(%p)\n", addr); \ |
164 |
+ ret = open(non_const_ptr(addr), O_RDONLY); \ |
165 |
+ assert(ret == -1 && errno == EFAULT); \ |
166 |
+}) |
167 |
+ |
168 |
+int main(int argc, char *argv[]) |
169 |
+{ |
170 |
+ int ret; |
171 |
+ char *path = PTR_ALIGN_UP((char *)buf, SIZE); |
172 |
+ size_t start, end; |
173 |
+ |
174 |
+ setbuf(stdout, NULL); |
175 |
+ |
176 |
+ printf("some bad pointers\n"); |
177 |
+ check_ptr(NULL); |
178 |
+ check_ptr((void *)-1); |
179 |
+ |
180 |
+ printf("lots of good pointers\n"); |
181 |
+ printf(" buf = %p\n", buf); |
182 |
+ printf(" path = %p\n", path); |
183 |
+ |
184 |
+ for (start = 0; start < SIZE * 2 + STRIDE; start += STRIDE) { |
185 |
+ char *p = path + start; |
186 |
+ for (end = start + STRIDE; end < SIZE * 2 + STRIDE; end += STRIDE) { |
187 |
+ size_t len = end - start; |
188 |
+ printf(" open(%p -> %p [+%#zx])\n", p, p + len, len); |
189 |
+ memset(p, 'a', len); |
190 |
+ path[end] = '\0'; |
191 |
+ ret = open(p, O_RDONLY); |
192 |
+ assert(ret == -1 && (errno == ENOENT || errno == ENAMETOOLONG)); |
193 |
+ } |
194 |
+ } |
195 |
+ |
196 |
+ return 0; |
197 |
+} |