libsandbox: add x32 ABI support v2.6
authorMike Frysinger <vapier@gentoo.org>
Wed, 7 Dec 2011 18:18:29 +0000 (13:18 -0500)
committerMike Frysinger <vapier@gentoo.org>
Tue, 3 Jul 2012 18:27:45 +0000 (14:27 -0400)
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>
configure.ac
libsandbox/libsandbox.h
libsandbox/trace.c
libsandbox/trace/linux/i386.c
libsandbox/trace/linux/x86_64.c
libsandbox/wrapper-funcs/__wrapper_exec.c
tests/script-0

index 26f6822..3bf3a8c 100644 (file)
@@ -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
index 38e983d..76dd8c8 100644 (file)
@@ -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 */
index f2071e0..ea769fd 100644 (file)
@@ -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
index f214026..d7b9eaa 100644 (file)
@@ -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
 
index 9b7e4ea..5bd1361 100644 (file)
@@ -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);
index c3536c3..0ffc08a 100644 (file)
@@ -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:
index 7e6bde6..b25032f 100755 (executable)
@@ -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