summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger2011-12-07 18:18:29 (GMT)
committerMike Frysinger2012-07-03 18:27:45 (GMT)
commit106c4cb4b1dd814fc29c56269dc964d03dadde15 (patch)
tree4bbb6ea08ad20ba0a4013e88353cd02f8bf87984
parent731630b7470b2b7ae3c055779138460d14d9fcd5 (diff)
libsandbox: add x32 ABI supportv2.6
We can trace x32 when the host is x86_64 or x32, but x32 cannot trace x86_64 due to limitations in the kernel interface -- all pointers get truncated to 32bits. We'll have to add external ptrace helpers in the future to make this work, but for now, we'll just let x86_64 code run unchecked :(. URL: https://bugs.gentoo.org/394179 Signed-off-by: Mike Frysinger <vapier@gentoo.org>
-rw-r--r--configure.ac2
-rw-r--r--libsandbox/libsandbox.h1
-rw-r--r--libsandbox/trace.c21
-rw-r--r--libsandbox/trace/linux/i386.c10
-rw-r--r--libsandbox/trace/linux/x86_64.c48
-rw-r--r--libsandbox/wrapper-funcs/__wrapper_exec.c4
-rwxr-xr-xtests/script-04
7 files changed, 78 insertions, 12 deletions
diff --git a/configure.ac b/configure.ac
index 26f6822..3bf3a8c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -46,7 +46,7 @@ AC_ARG_ENABLE([schizo],
SB_SCHIZO_SETTINGS="no"
if test "x$enable_schizo" = "xyes" ; then
case $host_alias in
- x86_64*linux*) SB_SCHIZO_SETTINGS="x86_64:-m64 x86:-m32";;
+ x86_64*linux*) SB_SCHIZO_SETTINGS="x86_64:-m64 x86:-m32 x32:-mx32";;
esac
fi
if test "$SB_SCHIZO_SETTINGS" != "no" ; then
diff --git a/libsandbox/libsandbox.h b/libsandbox/libsandbox.h
index 38e983d..76dd8c8 100644
--- a/libsandbox/libsandbox.h
+++ b/libsandbox/libsandbox.h
@@ -61,6 +61,7 @@ extern pid_t trace_pid;
extern void sb_lock(void);
extern void sb_unlock(void);
+bool trace_possible(const char *filename, char *const argv[], const void *data);
void trace_main(const char *filename, char *const argv[]);
/* glibc modified realpath() function */
diff --git a/libsandbox/trace.c b/libsandbox/trace.c
index f2071e0..ea769fd 100644
--- a/libsandbox/trace.c
+++ b/libsandbox/trace.c
@@ -11,6 +11,7 @@
static long _do_ptrace(enum __ptrace_request request, const char *srequest, void *addr, void *data);
#define do_ptrace(request, addr, data) _do_ptrace(request, #request, addr, data)
+#define _trace_possible(data) true
#ifdef DEBUG
# define SBDEBUG 1
@@ -485,6 +486,16 @@ void trace_main(const char *filename, char *const argv[])
#else
+#undef _trace_possible
+#define _trace_possible(data) false
+
+void trace_main(const char *filename, char *const argv[])
+{
+ /* trace_possible() triggers a warning for us */
+}
+
+#endif
+
static char *flatten_args(char *const argv[])
{
char *ret;
@@ -512,11 +523,13 @@ static char *flatten_args(char *const argv[])
return ret;
}
-void trace_main(const char *filename, char *const argv[])
+bool trace_possible(const char *filename, char *const argv[], const void *data)
{
+ if (_trace_possible(data))
+ return true;
+
char *args = flatten_args(argv);
- sb_eqawarn("Static ELF: %s: %s\n", filename, args);
+ sb_eqawarn("Unable to trace static ELF: %s: %s\n", filename, args);
free(args);
+ return false;
}
-
-#endif
diff --git a/libsandbox/trace/linux/i386.c b/libsandbox/trace/linux/i386.c
index f214026..d7b9eaa 100644
--- a/libsandbox/trace/linux/i386.c
+++ b/libsandbox/trace/linux/i386.c
@@ -1,3 +1,13 @@
+#undef _trace_possible
+#define _trace_possible _trace_possible
+static bool _trace_possible(const void *data)
+{
+ /* i386 can only trace i386 :( */
+ const Elf64_Ehdr *ehdr = data;
+ return (ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
+ (ehdr->e_machine == EM_386);
+}
+
#define trace_reg_sysnum orig_eax
#define trace_reg_ret eax
diff --git a/libsandbox/trace/linux/x86_64.c b/libsandbox/trace/linux/x86_64.c
index 9b7e4ea..5bd1361 100644
--- a/libsandbox/trace/linux/x86_64.c
+++ b/libsandbox/trace/linux/x86_64.c
@@ -1,3 +1,6 @@
+#undef _trace_possible
+#define _trace_possible _trace_possible
+
#ifdef SB_SCHIZO
static const struct syscall_entry syscall_table_32[] = {
@@ -12,20 +15,51 @@ static const struct syscall_entry syscall_table_64[] = {
#undef S
{ SB_NR_UNDEF, SB_NR_UNDEF, NULL },
};
+static const struct syscall_entry syscall_table_x32[] = {
+#define S(s) { SB_SYS_x32_##s, SB_NR_##s, #s },
+#include "trace_syscalls_x32.h"
+#undef S
+ { SB_NR_UNDEF, SB_NR_UNDEF, NULL },
+};
static bool pers_is_32(trace_regs *regs)
{
switch (regs->cs) {
case 0x23: return true;
case 0x33: return false;
- default: sb_ebort("unknown x86_64 personality");
+ default: sb_ebort("unknown x86_64 (CS) personality");
+ }
+}
+
+static bool pers_is_x32(trace_regs *regs)
+{
+ switch (regs->ds) {
+ case 0x2b: return true;
+ case 0x00: return false;
+ default: sb_ebort("unknown x86_64 (DS) personality");
}
}
static const struct syscall_entry *trace_check_personality(void *vregs)
{
trace_regs *regs = vregs;
- return pers_is_32(regs) ? syscall_table_32 : syscall_table_64;
+ if (pers_is_32(regs))
+ return syscall_table_32;
+ else if (pers_is_x32(regs))
+ return syscall_table_x32;
+ else
+ return syscall_table_64;
+}
+
+static bool _trace_possible(const void *data)
+{
+ /* x86_64 can trace anything, but x32 can't trace x86_64 */
+#if defined(__x86_64__) && defined(__ILP32__)
+ const Elf64_Ehdr *ehdr = data;
+ return (ehdr->e_ident[EI_CLASS] == ELFCLASS32);
+#else
+ return true;
+#endif
}
#else
@@ -35,6 +69,13 @@ static bool pers_is_32(trace_regs *regs)
return false;
}
+static bool _trace_possible(const void *data)
+{
+ const Elf64_Ehdr *ehdr = data;
+ return (ehdr->e_ident[EI_CLASS] == ELFCLASS64) &&
+ (ehdr->e_machine == EM_X86_64);
+}
+
#endif
#define trace_reg_sysnum orig_rax
@@ -56,6 +97,7 @@ static unsigned long trace_arg(void *vregs, int num)
{
trace_regs *regs = vregs;
if (pers_is_32(regs))
+ /* 32bit x86 */
switch (num) {
case 1: return regs->rbx;
case 2: return regs->rcx;
@@ -82,7 +124,7 @@ static void trace_dump_regs(void *vregs)
{
trace_regs *regs = vregs;
sb_printf("{ ");
-#define D(r) sb_printf(#r":%lu ", regs->r)
+#define D(r) sb_printf(#r":%"PRIu64" ", regs->r)
D(rax);
D(rdi);
D(rsi);
diff --git a/libsandbox/wrapper-funcs/__wrapper_exec.c b/libsandbox/wrapper-funcs/__wrapper_exec.c
index c3536c3..0ffc08a 100644
--- a/libsandbox/wrapper-funcs/__wrapper_exec.c
+++ b/libsandbox/wrapper-funcs/__wrapper_exec.c
@@ -33,7 +33,7 @@ static void sb_check_exec(const char *filename, char *const argv[])
return;
if (stat(filename, &st))
goto out_fd;
- if (st.st_size < EI_NIDENT)
+ if (st.st_size < sizeof(Elf64_Ehdr))
goto out_fd;
elf = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (elf == MAP_FAILED)
@@ -65,7 +65,7 @@ static void sb_check_exec(const char *filename, char *const argv[])
else
PARSE_ELF(64);
- do_trace = true;
+ do_trace = trace_possible(filename, argv, elf);
/* Now that we're done with stuff, clean up before forking */
done:
diff --git a/tests/script-0 b/tests/script-0
index 7e6bde6..b25032f 100755
--- a/tests/script-0
+++ b/tests/script-0
@@ -1,6 +1,6 @@
#!/bin/sh
# shell scripts only get properly wrapped if our native shell is the
# same abi as the compiled libsandbox #259244
-sh=$(scanelf -BF'%M#F' /bin/sh)
-sb=$(scanelf -BF'%M#F' "${abs_top_builddir}"/libsandbox/.libs/libsandbox.so)
+sh=$(scanelf -BF'%M %a#F' /bin/sh)
+sb=$(scanelf -BF'%M %a#F' "${abs_top_builddir}"/libsandbox/.libs/libsandbox.so)
[ "${sh}" = "${sb}" ] && exit 0 || exit 77