From decbad6a35bb3ad6e34d03a6d7e67466f9e5ba31 Mon Sep 17 00:00:00 2001 From: Stacey Son Date: Sun, 26 May 2013 20:39:26 -0500 Subject: [PATCH 08/23] bsd-user: initialize stack with signal trampolin code and canary To: Cc: Put full path for target executable, signal trampolin code, and stack canary on the stack in addition to just simply coping argv and env values. Signed-off-by: Stacey Son --- bsd-user/elfload.c | 32 +++----- bsd-user/freebsd/target_os_stack.h | 124 +++++++++++++++++++++++++++++++ bsd-user/i386/target_arch_sigtramp.h | 11 +++ bsd-user/mips/target_arch_signal.h | 2 +- bsd-user/mips/target_arch_sigtramp.h | 23 ++++++ bsd-user/mips64/target_arch_sigtramp.h | 23 ++++++ bsd-user/netbsd/target_os_stack.h | 31 ++++++++ bsd-user/openbsd/target_os_stack.h | 31 ++++++++ bsd-user/sparc/target_arch_sigtramp.h | 11 +++ bsd-user/sparc64/target_arch_sigtramp.h | 11 +++ bsd-user/x86_64/target_arch_sigtramp.h | 11 +++ 11 files changed, 289 insertions(+), 21 deletions(-) create mode 100644 bsd-user/freebsd/target_os_stack.h create mode 100644 bsd-user/i386/target_arch_sigtramp.h create mode 100644 bsd-user/mips/target_arch_sigtramp.h create mode 100644 bsd-user/mips64/target_arch_sigtramp.h create mode 100644 bsd-user/netbsd/target_os_stack.h create mode 100644 bsd-user/openbsd/target_os_stack.h create mode 100644 bsd-user/sparc/target_arch_sigtramp.h create mode 100644 bsd-user/sparc64/target_arch_sigtramp.h create mode 100644 bsd-user/x86_64/target_arch_sigtramp.h diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c index 8c8ed6a..0cd5fc4 100644 --- a/bsd-user/elfload.c +++ b/bsd-user/elfload.c @@ -27,6 +27,7 @@ #include "qemu.h" #include "disas/disas.h" +#include "target_os_stack.h" #ifdef _ARCH_PPC64 #undef ARCH_DLINFO @@ -712,38 +713,29 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page, static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm, struct image_info *info) { - abi_ulong stack_base, size, error; - int i; + abi_ulong stack_base, size; + abi_long addr; /* Create enough stack to hold everything. If we don't use * it for args, we'll use it for something else... */ size = target_dflssiz; stack_base = TARGET_USRSTACK - size; - error = target_mmap(0, - size + qemu_host_page_size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, - -1, 0); - if (error == -1) { + addr = target_mmap(stack_base , size + qemu_host_page_size, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + if (addr == -1) { perror("stk mmap"); exit(-1); } /* we reserve one extra page at the top of the stack as guard */ - target_mprotect(error + size, qemu_host_page_size, PROT_NONE); - - stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE; - p += stack_base; + target_mprotect(addr + size, qemu_host_page_size, PROT_NONE); - for (i = 0 ; i < MAX_ARG_PAGES ; i++) { - if (bprm->page[i]) { - info->rss++; - /* FIXME - check return value of memcpy_to_target() for failure */ - memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE); - g_free(bprm->page[i]); - } - stack_base += TARGET_PAGE_SIZE; + p = setup_initial_stack(p, bprm, stack_base, size, addr); + if (p == 0) { + perror("stk setup"); + exit(-1); } + return p; } diff --git a/bsd-user/freebsd/target_os_stack.h b/bsd-user/freebsd/target_os_stack.h new file mode 100644 index 0000000..f600009 --- /dev/null +++ b/bsd-user/freebsd/target_os_stack.h @@ -0,0 +1,124 @@ +#ifndef _TARGET_OS_STACK_H_ +#define _TARGET_OS_STACK_H_ + +#include +#include "target_arch_sigtramp.h" + +/* + * The inital FreeBSD stack is as follows: + * (see kern/kern_exec.c exec_copyout_strings() ) + * + * Hi Address -> char **ps_argvstr (struct ps_strings for ps, w, etc.) + * unsigned ps_nargvstr + * char **ps_envstr + * PS_STRINGS -> unsigned ps_nenvstr + * + * machine dependent sigcode (sv_sigcode of size + * sv_szsigcode) + * + * execpath (absolute image path for rtld) + * + * SSP Canary (sizeof(long) * 8) + * + * page sizes array (usually sizeof(u_long) ) + * + * "destp" -> argv, env strings (up to 262144 bytes) + */ +static inline abi_ulong setup_initial_stack(abi_ulong p, + struct bsd_binprm *bprm, abi_ulong stack_base, abi_ulong size, + abi_ulong addr) +{ + int i; + abi_ulong stack_hi_addr; + size_t execpath_len; + abi_ulong destp, argvp, envp; + struct target_ps_strings ps_strs; + char canary[sizeof(abi_long) * 8]; + + stack_hi_addr = p = addr + size; + + /* Save some space for ps_strings. */ + p -= sizeof(struct target_ps_strings); + +#ifdef TARGET_SZSIGCODE + /* Add machine depedent sigcode. */ + p -= TARGET_SZSIGCODE; + if (setup_sigtramp(p, (unsigned)offsetof(struct target_sigframe, sf_uc), + TARGET_FREEBSD_NR_sigreturn)) { + return 0; + } +#endif + if (bprm->fullpath) { + execpath_len = strlen(bprm->fullpath) + 1; + p -= roundup(execpath_len, sizeof(abi_ulong)); + if (memcpy_to_target(p, bprm->fullpath, execpath_len)) { + return 0; + } + } + /* Add canary for SSP. */ + arc4random_buf(canary, sizeof(canary)); + p -= roundup(sizeof(canary), sizeof(abi_ulong)); + if (memcpy_to_target(p, canary, sizeof(canary))) { + return 0; + } + /* Add page sizes array. */ + p -= sizeof(abi_ulong); + if (put_user_ual(TARGET_PAGE_SIZE, p)) { + return 0; + } + argvp = p - TARGET_SPACE_USRSPACE; + p = destp = p - TARGET_SPACE_USRSPACE - TARGET_ARG_MAX; + /* XXX check strlen(argv and envp strings) < TARGET_ARG_MAX ? */ + + /* + * Add argv strings. Note that the argv[] vectors are added by + * loader_build_argptr() + */ + envp = argvp + (bprm->argc + 2) * sizeof(abi_ulong); + ps_strs.ps_argvstr = tswapl(argvp); + ps_strs.ps_nargvstr = tswap32(bprm->argc); + for (i = 0; i < bprm->argc; ++i) { + size_t len = strlen(bprm->argv[i]) + 1; + + if (memcpy_to_target(destp, bprm->argv[i], len)) { + return 0; + } + if (put_user_ual(destp, argvp)) { + return 0; + } + argvp += sizeof(abi_ulong); + destp += len; + } + if (put_user_ual(0, argvp)) { + return 0; + } + /* + * Add env strings. Note that the envp[] vectors are added by + * loader_build_argptr(). + */ + ps_strs.ps_envstr = tswapl(envp); + ps_strs.ps_nenvstr = tswap32(bprm->envc); + for (i = 0; i < bprm->envc; ++i) { + size_t len = strlen(bprm->envp[i]) + 1; + + if (memcpy_to_target(destp, bprm->envp[i], len)) { + return 0; + } + if (put_user_ual(destp, envp)) { + return 0; + } + envp += sizeof(abi_ulong); + destp += len; + } + if (put_user_ual(0, envp)) { + return 0; + } + if (memcpy_to_target(stack_hi_addr - sizeof(ps_strs), &ps_strs, + sizeof(ps_strs))) { + return 0; + } + + return p; + } + +#endif /* !_TARGET_OS_STACK_H_ */ diff --git a/bsd-user/i386/target_arch_sigtramp.h b/bsd-user/i386/target_arch_sigtramp.h new file mode 100644 index 0000000..f0f36d1 --- /dev/null +++ b/bsd-user/i386/target_arch_sigtramp.h @@ -0,0 +1,11 @@ + +#ifndef _TARGET_ARCH_SIGTRAMP_H_ +#define _TARGET_ARCH_SIGTRAMP_H_ + +static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, + unsigned sys_sigreturn) +{ + + return -TARGET_EOPNOTSUPP; +} +#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ diff --git a/bsd-user/mips/target_arch_signal.h b/bsd-user/mips/target_arch_signal.h index cc7e750..f68034f 100644 --- a/bsd-user/mips/target_arch_signal.h +++ b/bsd-user/mips/target_arch_signal.h @@ -22,7 +22,7 @@ #define TARGET_INSN_SIZE 4 /* mips instruction size */ -/* Size of the signal trampolin code placed on the stack. */ +/* Size of the signal trampolin code. See insall_sigtramp(). */ #define TARGET_SZSIGCODE ((abi_ulong)(4 * TARGET_INSN_SIZE)) /* compare to mips/include/_limits.h */ diff --git a/bsd-user/mips/target_arch_sigtramp.h b/bsd-user/mips/target_arch_sigtramp.h new file mode 100644 index 0000000..5e3c69a --- /dev/null +++ b/bsd-user/mips/target_arch_sigtramp.h @@ -0,0 +1,23 @@ + +#ifndef _TARGET_ARCH_SIGTRAMP_H_ +#define _TARGET_ARCH_SIGTRAMP_H_ + +/* Compare to mips/mips/locore.S sigcode() */ +static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, + unsigned sys_sigreturn) +{ + int i; + uint32_t sigtramp_code[TARGET_SZSIGCODE/TARGET_INSN_SIZE] = { + /* 1 */ 0x67A40000 + sigf_uc, /* daddu $a0, $sp, (sigf_uc) */ + /* 2 */ 0x24020000 + sys_sigreturn, /* li $v0, (sys_sigreturn) */ + /* 3 */ 0x0000000C, /* syscall */ + /* 4 */ 0x0000000D /* break */ + }; + + for (i = 0; i < 4; i++) { + tswap32s(&sigtramp_code[i]); + } + + return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE); +} +#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ diff --git a/bsd-user/mips64/target_arch_sigtramp.h b/bsd-user/mips64/target_arch_sigtramp.h new file mode 100644 index 0000000..5e3c69a --- /dev/null +++ b/bsd-user/mips64/target_arch_sigtramp.h @@ -0,0 +1,23 @@ + +#ifndef _TARGET_ARCH_SIGTRAMP_H_ +#define _TARGET_ARCH_SIGTRAMP_H_ + +/* Compare to mips/mips/locore.S sigcode() */ +static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, + unsigned sys_sigreturn) +{ + int i; + uint32_t sigtramp_code[TARGET_SZSIGCODE/TARGET_INSN_SIZE] = { + /* 1 */ 0x67A40000 + sigf_uc, /* daddu $a0, $sp, (sigf_uc) */ + /* 2 */ 0x24020000 + sys_sigreturn, /* li $v0, (sys_sigreturn) */ + /* 3 */ 0x0000000C, /* syscall */ + /* 4 */ 0x0000000D /* break */ + }; + + for (i = 0; i < 4; i++) { + tswap32s(&sigtramp_code[i]); + } + + return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE); +} +#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ diff --git a/bsd-user/netbsd/target_os_stack.h b/bsd-user/netbsd/target_os_stack.h new file mode 100644 index 0000000..a852ae6 --- /dev/null +++ b/bsd-user/netbsd/target_os_stack.h @@ -0,0 +1,31 @@ +#ifndef _TARGET_OS_STACK_H_ +#define _TARGET_OS_STACK_H_ + +#include "target_arch_sigtramp.h" + +static inline abi_ulong setup_initial_stack(abi_ulong p, + struct bsd_binprm *bprm, abi_ulong sbase, abi_ulong size, + abi_ulong addr) +{ + int i; + abi_ulong stack_base; + + stack_base = addr + size - MAX_ARG_PAGES * TARGET_PAGE_SIZE; + p += stack_base; + + for (i = 0; i < MAX_ARG_PAGES; i++) { + if (bprm->page[i]) { + info->rss++; + if (!memcpy_to_target(stack_base, bprm->page[i], + TARGET_PAGE_SIZE)) { + return 0; + } + g_free(bprm->page[i]); + } + stack_base += TARGET_PAGE_SIZE; + } + + return p; +} + +#endif /* !_TARGET_OS_STACK_H_ */ diff --git a/bsd-user/openbsd/target_os_stack.h b/bsd-user/openbsd/target_os_stack.h new file mode 100644 index 0000000..a852ae6 --- /dev/null +++ b/bsd-user/openbsd/target_os_stack.h @@ -0,0 +1,31 @@ +#ifndef _TARGET_OS_STACK_H_ +#define _TARGET_OS_STACK_H_ + +#include "target_arch_sigtramp.h" + +static inline abi_ulong setup_initial_stack(abi_ulong p, + struct bsd_binprm *bprm, abi_ulong sbase, abi_ulong size, + abi_ulong addr) +{ + int i; + abi_ulong stack_base; + + stack_base = addr + size - MAX_ARG_PAGES * TARGET_PAGE_SIZE; + p += stack_base; + + for (i = 0; i < MAX_ARG_PAGES; i++) { + if (bprm->page[i]) { + info->rss++; + if (!memcpy_to_target(stack_base, bprm->page[i], + TARGET_PAGE_SIZE)) { + return 0; + } + g_free(bprm->page[i]); + } + stack_base += TARGET_PAGE_SIZE; + } + + return p; +} + +#endif /* !_TARGET_OS_STACK_H_ */ diff --git a/bsd-user/sparc/target_arch_sigtramp.h b/bsd-user/sparc/target_arch_sigtramp.h new file mode 100644 index 0000000..f0f36d1 --- /dev/null +++ b/bsd-user/sparc/target_arch_sigtramp.h @@ -0,0 +1,11 @@ + +#ifndef _TARGET_ARCH_SIGTRAMP_H_ +#define _TARGET_ARCH_SIGTRAMP_H_ + +static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, + unsigned sys_sigreturn) +{ + + return -TARGET_EOPNOTSUPP; +} +#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ diff --git a/bsd-user/sparc64/target_arch_sigtramp.h b/bsd-user/sparc64/target_arch_sigtramp.h new file mode 100644 index 0000000..f0f36d1 --- /dev/null +++ b/bsd-user/sparc64/target_arch_sigtramp.h @@ -0,0 +1,11 @@ + +#ifndef _TARGET_ARCH_SIGTRAMP_H_ +#define _TARGET_ARCH_SIGTRAMP_H_ + +static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, + unsigned sys_sigreturn) +{ + + return -TARGET_EOPNOTSUPP; +} +#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ diff --git a/bsd-user/x86_64/target_arch_sigtramp.h b/bsd-user/x86_64/target_arch_sigtramp.h new file mode 100644 index 0000000..f0f36d1 --- /dev/null +++ b/bsd-user/x86_64/target_arch_sigtramp.h @@ -0,0 +1,11 @@ + +#ifndef _TARGET_ARCH_SIGTRAMP_H_ +#define _TARGET_ARCH_SIGTRAMP_H_ + +static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc, + unsigned sys_sigreturn) +{ + + return -TARGET_EOPNOTSUPP; +} +#endif /* _TARGET_ARCH_SIGTRAMP_H_ */ -- 1.7.8