cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

target_os_stack.h (5577B)


      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 */
     47static 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_ */