aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2015-09-20 18:25:33 -0400
committerMike Frysinger <vapier@gentoo.org>2015-09-20 18:25:33 -0400
commit0a9188fd0a812cb864819d37a6a7217a135b85f0 (patch)
tree24ebd8744cd6758e86a0e78c91448012c73da917
parentlibsandbox: fix process_vm_readv addresses/lengths (diff)
downloadsandbox-0a9188fd0a812cb864819d37a6a7217a135b85f0.tar.gz
sandbox-0a9188fd0a812cb864819d37a6a7217a135b85f0.tar.bz2
sandbox-0a9188fd0a812cb864819d37a6a7217a135b85f0.zip
libsandbox: do not abort when the target uses bad pointers
If the target passes a bad pointer to the kernel, then trying to extract the data via ptrace will also throw an error. The tracing code should not abort though as there's no valid address to check, and kernel itself will return an error for us. Simply return and move on. URL: https://bugs.gentoo.org/560396 Reported-by: Jeroen Roovers <jer@gentoo.org> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
-rw-r--r--libsandbox/trace.c14
-rw-r--r--localdecls.h4
-rw-r--r--tests/Makefile.am3
-rwxr-xr-xtests/script-13.sh5
-rw-r--r--tests/script.at1
-rw-r--r--tests/tests.h4
-rw-r--r--tests/trace-memory_static_tst.c62
7 files changed, 92 insertions, 1 deletions
diff --git a/libsandbox/trace.c b/libsandbox/trace.c
index 99ef8cd..f9194fe 100644
--- a/libsandbox/trace.c
+++ b/libsandbox/trace.c
@@ -59,6 +59,11 @@ static long _do_ptrace(enum __ptrace_request request, const char *srequest, void
}
sched_yield();
goto try_again;
+ } else if (errno == EIO || errno == EFAULT) {
+ /* This comes up when the child itself tries to use a bad pointer.
+ * That's not something the sandbox should abort on. #560396
+ */
+ return ret;
} else if (!errno)
if (request == PTRACE_PEEKDATA ||
request == PTRACE_PEEKTEXT ||
@@ -140,7 +145,16 @@ static char *do_peekstr(unsigned long lptr)
while (1) {
a = lptr & (sizeof(long) - 1);
lptr -= a;
+ errno = 0;
s.val = do_peekdata(lptr);
+ if (unlikely(errno)) {
+ if (errno == EIO || errno == EFAULT) {
+ ret[0] = '\0';
+ return ret;
+ }
+ sb_ebort("ISE:do_peekstr:do_peekdata(%#lx) failed: %s\n",
+ lptr, strerror(errno));
+ }
for (i = a; i < sizeof(long); ++i) {
ret[l++] = s.x[i];
if (!s.x[i])
diff --git a/localdecls.h b/localdecls.h
index 0e11fea..ecc5856 100644
--- a/localdecls.h
+++ b/localdecls.h
@@ -102,6 +102,10 @@ typedef struct user_regs_struct trace_regs;
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
+#define ALIGN_DOWN(base, size) ((base) & -(size))
+#define ALIGN_UP(base, size) ALIGN_DOWN((base) + (size) - 1, (size))
+#define PTR_ALIGN_DOWN(base, size) ((__typeof__(base))ALIGN_DOWN((uintptr_t)(base), (size)))
+#define PTR_ALIGN_UP(base, size) ((__typeof__(base))ALIGN_UP((uintptr_t)(base), (size)))
/* If the system is old and does not support *at funcs, then define
* it ourself. Shouldn't matter based on how we use it.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0f0c249..3627344 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -76,7 +76,8 @@ check_PROGRAMS = \
pipe-fork_static_tst \
sb_printf_tst \
sigsuspend-zsh_tst \
- sigsuspend-zsh_static_tst
+ sigsuspend-zsh_static_tst \
+ trace-memory_static_tst
dist_check_SCRIPTS = \
$(wildcard $(srcdir)/*-[0-9]*.sh) \
diff --git a/tests/script-13.sh b/tests/script-13.sh
new file mode 100755
index 0000000..24a0e3b
--- /dev/null
+++ b/tests/script-13.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# make sure poking remote addresses works even when they're bad/unaligned #560396
+[ "${at_xfail}" = "yes" ] && exit 77 # see script-0
+
+trace-memory_static_tst
diff --git a/tests/script.at b/tests/script.at
index f07a8f1..58a5077 100644
--- a/tests/script.at
+++ b/tests/script.at
@@ -10,3 +10,4 @@ SB_CHECK(9, [wait errpipe... done OK!])
SB_CHECK(10)
SB_CHECK(11)
SB_CHECK(12)
+SB_CHECK(13)
diff --git a/tests/tests.h b/tests/tests.h
index 72c678c..51dc68a 100644
--- a/tests/tests.h
+++ b/tests/tests.h
@@ -1,5 +1,9 @@
#include "headers.h"
+/* Make sure assert() works in tests. */
+#undef NDEBUG
+#include <assert.h>
+
#define _msg(std, fmt, args...) fprintf(std, "%s:%s():%i: " fmt "\n", __FILE__, __func__, __LINE__, ##args)
#define _stderr_msg(fmt, args...) _msg(stderr, fmt, ##args)
#define _stderr_pmsg(fmt, args...) _msg(stderr, fmt ": %s", ##args, strerror(errno))
diff --git a/tests/trace-memory_static_tst.c b/tests/trace-memory_static_tst.c
new file mode 100644
index 0000000..14c6477
--- /dev/null
+++ b/tests/trace-memory_static_tst.c
@@ -0,0 +1,62 @@
+/*
+ * Make sure the process_vm_readv func can work with strings with different
+ * alignments and lengths.
+ *
+ * https://bugs.gentoo.org/560396
+ */
+
+/* We want to make some bad calls. */
+#undef _FORTIFY_SOURCES
+
+#include "tests.h"
+
+/* Make sure the buffer spans multiple pages. */
+#define SIZE 0x1000
+/* Make sure the buffer has plenty of slack space before/after. */
+static char buf[SIZE * 8];
+
+/* The smaller the span, the # of calls goes up: O(N*N*2+N). */
+#define COUNT 0x20
+#define STRIDE (SIZE / COUNT)
+
+/* Some hacks to defeat gcc warnings so we can use bad pointers. */
+volatile uintptr_t offset = 0;
+#define non_const_ptr(ptr) ((void *)((uintptr_t)(ptr) + offset))
+
+#define check_ptr(addr) \
+({ \
+ printf(" open(%p)\n", addr); \
+ ret = open(non_const_ptr(addr), O_RDONLY); \
+ assert(ret == -1 && errno == EFAULT); \
+})
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ char *path = PTR_ALIGN_UP((char *)buf, SIZE);
+ size_t start, end;
+
+ setbuf(stdout, NULL);
+
+ printf("some bad pointers\n");
+ check_ptr(NULL);
+ check_ptr((void *)-1);
+
+ printf("lots of good pointers\n");
+ printf(" buf = %p\n", buf);
+ printf(" path = %p\n", path);
+
+ for (start = 0; start < SIZE * 2 + STRIDE; start += STRIDE) {
+ char *p = path + start;
+ for (end = start + STRIDE; end < SIZE * 2 + STRIDE; end += STRIDE) {
+ size_t len = end - start;
+ printf(" open(%p -> %p [+%#zx])\n", p, p + len, len);
+ memset(p, 'a', len);
+ path[end] = '\0';
+ ret = open(p, O_RDONLY);
+ assert(ret == -1 && (errno == ENOENT || errno == ENAMETOOLONG));
+ }
+ }
+
+ return 0;
+}