qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

target_os_stack.h (5570B)


      1 /*
      2  *  FreeBSD setup_initial_stack() implementation.
      3  *
      4  *  Copyright (c) 2013-14 Stacey D. Son
      5  *
      6  *  This program is free software; you can redistribute it and/or modify
      7  *  it under the terms of the GNU General Public License as published by
      8  *  the Free Software Foundation; either version 2 of the License, or
      9  *  (at your option) any later version.
     10  *
     11  *  This program is distributed in the hope that it will be useful,
     12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  *  GNU General Public License for more details.
     15  *
     16  *  You should have received a copy of the GNU General Public License
     17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
     18  */
     19 
     20 #ifndef TARGET_OS_STACK_H
     21 #define TARGET_OS_STACK_H
     22 
     23 #include <sys/param.h>
     24 #include "target_arch_sigtramp.h"
     25 #include "qemu/guest-random.h"
     26 
     27 /*
     28  * The inital FreeBSD stack is as follows:
     29  * (see kern/kern_exec.c exec_copyout_strings() )
     30  *
     31  *  Hi Address -> char **ps_argvstr  (struct ps_strings for ps, w, etc.)
     32  *                unsigned ps_nargvstr
     33  *                char **ps_envstr
     34  *  PS_STRINGS -> unsigned ps_nenvstr
     35  *
     36  *                machine dependent sigcode (sv_sigcode of size
     37  *                                           sv_szsigcode)
     38  *
     39  *                execpath          (absolute image path for rtld)
     40  *
     41  *                SSP Canary        (sizeof(long) * 8)
     42  *
     43  *                page sizes array  (usually sizeof(u_long) )
     44  *
     45  *  "destp" ->    argv, env strings (up to 262144 bytes)
     46  */
     47 static inline int setup_initial_stack(struct bsd_binprm *bprm,
     48         abi_ulong *ret_addr, abi_ulong *stringp)
     49 {
     50     int i;
     51     abi_ulong stack_hi_addr;
     52     size_t execpath_len, stringspace;
     53     abi_ulong destp, argvp, envp, p;
     54     struct target_ps_strings ps_strs;
     55     char canary[sizeof(abi_long) * 8];
     56 
     57     stack_hi_addr = p = target_stkbas + target_stksiz;
     58 
     59     /* Save some space for ps_strings. */
     60     p -= sizeof(struct target_ps_strings);
     61 
     62     /* Add machine depedent sigcode. */
     63     p -= TARGET_SZSIGCODE;
     64     if (setup_sigtramp(p, (unsigned)offsetof(struct target_sigframe, sf_uc),
     65             TARGET_FREEBSD_NR_sigreturn)) {
     66         errno = EFAULT;
     67         return -1;
     68     }
     69     if (bprm->fullpath) {
     70         execpath_len = strlen(bprm->fullpath) + 1;
     71         p -= roundup(execpath_len, sizeof(abi_ulong));
     72         if (memcpy_to_target(p, bprm->fullpath, execpath_len)) {
     73             errno = EFAULT;
     74             return -1;
     75         }
     76     }
     77     /* Add canary for SSP. */
     78     qemu_guest_getrandom_nofail(canary, sizeof(canary));
     79     p -= roundup(sizeof(canary), sizeof(abi_ulong));
     80     if (memcpy_to_target(p, canary, sizeof(canary))) {
     81         errno = EFAULT;
     82         return -1;
     83     }
     84     /* Add page sizes array. */
     85     p -= sizeof(abi_ulong);
     86     if (put_user_ual(TARGET_PAGE_SIZE, p)) {
     87         errno = EFAULT;
     88         return -1;
     89     }
     90     /*
     91      * Deviate from FreeBSD stack layout: force stack to new page here
     92      * so that signal trampoline is not sharing the page with user stack
     93      * frames. This is actively harmful in qemu as it marks pages with
     94      * code it translated as read-only, which is somewhat problematic
     95      * for user trying to use the stack as intended.
     96      */
     97     p = rounddown(p, TARGET_PAGE_SIZE);
     98 
     99     /* Calculate the string space needed */
    100     stringspace = 0;
    101     for (i = 0; i < bprm->argc; ++i) {
    102         stringspace += strlen(bprm->argv[i]) + 1;
    103     }
    104     for (i = 0; i < bprm->envc; ++i) {
    105         stringspace += strlen(bprm->envp[i]) + 1;
    106     }
    107     if (stringspace > TARGET_ARG_MAX) {
    108         errno = ENOMEM;
    109         return -1;
    110     }
    111     /* Make room for the argv and envp strings */
    112     destp = rounddown(p - stringspace, sizeof(abi_ulong));
    113     p = argvp = destp - (bprm->argc + bprm->envc + 2) * sizeof(abi_ulong);
    114     /* Remember the strings pointer */
    115     if (stringp) {
    116         *stringp = destp;
    117     }
    118     /*
    119      * Add argv strings.  Note that the argv[] vectors are added by
    120      * loader_build_argptr()
    121      */
    122     /* XXX need to make room for auxargs */
    123     ps_strs.ps_argvstr = tswapl(argvp);
    124     ps_strs.ps_nargvstr = tswap32(bprm->argc);
    125     for (i = 0; i < bprm->argc; ++i) {
    126         size_t len = strlen(bprm->argv[i]) + 1;
    127 
    128         if (memcpy_to_target(destp, bprm->argv[i], len)) {
    129             errno = EFAULT;
    130             return -1;
    131         }
    132         if (put_user_ual(destp, argvp)) {
    133             errno = EFAULT;
    134             return -1;
    135         }
    136         argvp += sizeof(abi_ulong);
    137         destp += len;
    138     }
    139     if (put_user_ual(0, argvp)) {
    140         errno = EFAULT;
    141         return -1;
    142     }
    143     /*
    144      * Add env strings. Note that the envp[] vectors are added by
    145      * loader_build_argptr().
    146      */
    147     envp = argvp + sizeof(abi_ulong);
    148     ps_strs.ps_envstr = tswapl(envp);
    149     ps_strs.ps_nenvstr = tswap32(bprm->envc);
    150     for (i = 0; i < bprm->envc; ++i) {
    151         size_t len = strlen(bprm->envp[i]) + 1;
    152 
    153         if (memcpy_to_target(destp, bprm->envp[i], len)) {
    154             errno = EFAULT;
    155             return -1;
    156         }
    157         if (put_user_ual(destp, envp)) {
    158             errno = EFAULT;
    159             return -1;
    160         }
    161         envp += sizeof(abi_ulong);
    162         destp += len;
    163     }
    164     if (put_user_ual(0, envp)) {
    165         errno = EFAULT;
    166         return -1;
    167     }
    168     if (memcpy_to_target(stack_hi_addr - sizeof(ps_strs), &ps_strs,
    169                 sizeof(ps_strs))) {
    170         errno = EFAULT;
    171         return -1;
    172     }
    173 
    174     if (ret_addr) {
    175         *ret_addr = p;
    176     }
    177 
    178     return 0;
    179  }
    180 
    181 #endif /* TARGET_OS_STACK_H */