123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- /*
- * FreeBSD setup_initial_stack() implementation.
- *
- * Copyright (c) 2013-14 Stacey D. Son
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
- #ifndef TARGET_OS_STACK_H
- #define TARGET_OS_STACK_H
- #include <sys/param.h>
- #include "target_arch_sigtramp.h"
- #include "qemu/guest-random.h"
- #include "user/tswap-target.h"
- /*
- * The initial 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 int setup_initial_stack(struct bsd_binprm *bprm,
- abi_ulong *ret_addr, abi_ulong *stringp)
- {
- int i;
- abi_ulong stack_hi_addr;
- size_t execpath_len, stringspace;
- abi_ulong destp, argvp, envp, p;
- struct target_ps_strings ps_strs;
- char canary[sizeof(abi_long) * 8];
- stack_hi_addr = p = target_stkbas + target_stksiz;
- /* Save some space for ps_strings. */
- p -= sizeof(struct target_ps_strings);
- /* Add machine dependent sigcode. */
- p -= TARGET_SZSIGCODE;
- if (setup_sigtramp(p, (unsigned)offsetof(struct target_sigframe, sf_uc),
- TARGET_FREEBSD_NR_sigreturn)) {
- errno = EFAULT;
- return -1;
- }
- 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)) {
- errno = EFAULT;
- return -1;
- }
- }
- /* Add canary for SSP. */
- qemu_guest_getrandom_nofail(canary, sizeof(canary));
- p -= roundup(sizeof(canary), sizeof(abi_ulong));
- if (memcpy_to_target(p, canary, sizeof(canary))) {
- errno = EFAULT;
- return -1;
- }
- /* Add page sizes array. */
- p -= sizeof(abi_ulong);
- if (put_user_ual(TARGET_PAGE_SIZE, p)) {
- errno = EFAULT;
- return -1;
- }
- /*
- * Deviate from FreeBSD stack layout: force stack to new page here
- * so that signal trampoline is not sharing the page with user stack
- * frames. This is actively harmful in qemu as it marks pages with
- * code it translated as read-only, which is somewhat problematic
- * for user trying to use the stack as intended.
- */
- p = rounddown(p, TARGET_PAGE_SIZE);
- /* Calculate the string space needed */
- stringspace = 0;
- for (i = 0; i < bprm->argc; ++i) {
- stringspace += strlen(bprm->argv[i]) + 1;
- }
- for (i = 0; i < bprm->envc; ++i) {
- stringspace += strlen(bprm->envp[i]) + 1;
- }
- if (stringspace > TARGET_ARG_MAX) {
- errno = ENOMEM;
- return -1;
- }
- /* Make room for the argv and envp strings */
- destp = rounddown(p - stringspace, sizeof(abi_ulong));
- p = argvp = destp - (bprm->argc + bprm->envc + 2) * sizeof(abi_ulong);
- /* Remember the strings pointer */
- if (stringp) {
- *stringp = destp;
- }
- /*
- * Add argv strings. Note that the argv[] vectors are added by
- * loader_build_argptr()
- */
- /* XXX need to make room for auxargs */
- 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)) {
- errno = EFAULT;
- return -1;
- }
- if (put_user_ual(destp, argvp)) {
- errno = EFAULT;
- return -1;
- }
- argvp += sizeof(abi_ulong);
- destp += len;
- }
- if (put_user_ual(0, argvp)) {
- errno = EFAULT;
- return -1;
- }
- /*
- * Add env strings. Note that the envp[] vectors are added by
- * loader_build_argptr().
- */
- envp = argvp + sizeof(abi_ulong);
- 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)) {
- errno = EFAULT;
- return -1;
- }
- if (put_user_ual(destp, envp)) {
- errno = EFAULT;
- return -1;
- }
- envp += sizeof(abi_ulong);
- destp += len;
- }
- if (put_user_ual(0, envp)) {
- errno = EFAULT;
- return -1;
- }
- if (memcpy_to_target(stack_hi_addr - sizeof(ps_strs), &ps_strs,
- sizeof(ps_strs))) {
- errno = EFAULT;
- return -1;
- }
- if (ret_addr) {
- *ret_addr = p;
- }
- return 0;
- }
- #endif /* TARGET_OS_STACK_H */
|