From patchwork Mon Jun 24 02:03:40 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stacey Son X-Patchwork-Id: 253913 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id B1DD62C0087 for ; Tue, 25 Jun 2013 02:51:08 +1000 (EST) Received: from localhost ([::1]:33041 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ur9ys-0002Mi-IY for incoming@patchwork.ozlabs.org; Mon, 24 Jun 2013 12:51:06 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42092) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ur9wS-0000jq-W9 for qemu-devel@nongnu.org; Mon, 24 Jun 2013 12:49:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Ur9wD-0005vx-AE for qemu-devel@nongnu.org; Mon, 24 Jun 2013 12:48:36 -0400 Received: from cdptpa-omtalb.mail.rr.com ([75.180.132.120]:47264) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ur9wD-0005tz-2N for qemu-devel@nongnu.org; Mon, 24 Jun 2013 12:48:21 -0400 X-Authority-Analysis: v=2.0 cv=Ev5QXFgA c=1 sm=0 a=Oa4axR4OH/tQIi4PbzyetA==:17 a=BzKiyTcfMA4A:10 a=ZuBy_wNGSIYA:10 a=dBRESv0yCI8A:10 a=6I5d2MoRAAAA:8 a=KGjhK52YXX0A:10 a=9KhJ-QPQMAcA:10 a=HA1DjnBr3KhNxLmiBrgA:9 a=SV7veod9ZcQA:10 a=Oa4axR4OH/tQIi4PbzyetA==:117 X-Cloudmark-Score: 0 X-Authenticated-User: X-Originating-IP: 76.187.137.252 Received: from [76.187.137.252] ([76.187.137.252:52974] helo=salmon.son.org) by cdptpa-oedge01.mail.rr.com (envelope-from ) (ecelerity 2.2.3.46 r()) with ESMTP id 34/AA-06197-35878C15; Mon, 24 Jun 2013 16:48:19 +0000 Received: from son.org (localhost [127.0.0.1]) by salmon.son.org (8.14.7/8.14.7) with ESMTP id r5O249mK042011; Sun, 23 Jun 2013 21:04:09 -0500 (CDT) (envelope-from sson@son.org) Received: (from sson@localhost) by son.org (8.14.7/8.14.7/Submit) id r5O249ei042010; Sun, 23 Jun 2013 21:04:09 -0500 (CDT) (envelope-from sson) From: Stacey Son To: qemu-devel@nongnu.org Date: Sun, 23 Jun 2013 21:03:40 -0500 Message-Id: <1372039435-41921-9-git-send-email-sson@FreeBSD.org> X-Mailer: git-send-email 1.7.8 In-Reply-To: <1372039435-41921-1-git-send-email-sson@FreeBSD.org> References: <1372039435-41921-1-git-send-email-sson@FreeBSD.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 75.180.132.120 Cc: Stacey Son Subject: [Qemu-devel] [PATCH 08/23] bsd-user: initialize stack with signal trampolin code and canary X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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_ */