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

syscall.c (16595B)


      1/*
      2 *  BSD syscalls
      3 *
      4 *  Copyright (c) 2003 - 2008 Fabrice Bellard
      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#include "qemu/osdep.h"
     20#include "qemu/cutils.h"
     21#include "qemu/path.h"
     22#include <sys/syscall.h>
     23#include <sys/param.h>
     24#include <sys/sysctl.h>
     25#include <utime.h>
     26
     27#include "qemu.h"
     28#include "qemu-common.h"
     29#include "user/syscall-trace.h"
     30
     31//#define DEBUG
     32
     33static abi_ulong target_brk;
     34static abi_ulong target_original_brk;
     35
     36static inline abi_long get_errno(abi_long ret)
     37{
     38    if (ret == -1)
     39        /* XXX need to translate host -> target errnos here */
     40        return -(errno);
     41    else
     42        return ret;
     43}
     44
     45#define target_to_host_bitmask(x, tbl) (x)
     46
     47static inline int is_error(abi_long ret)
     48{
     49    return (abi_ulong)ret >= (abi_ulong)(-4096);
     50}
     51
     52void target_set_brk(abi_ulong new_brk)
     53{
     54    target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
     55}
     56
     57/* do_obreak() must return target errnos. */
     58static abi_long do_obreak(abi_ulong new_brk)
     59{
     60    abi_ulong brk_page;
     61    abi_long mapped_addr;
     62    int new_alloc_size;
     63
     64    if (!new_brk)
     65        return 0;
     66    if (new_brk < target_original_brk)
     67        return -TARGET_EINVAL;
     68
     69    brk_page = HOST_PAGE_ALIGN(target_brk);
     70
     71    /* If the new brk is less than this, set it and we're done... */
     72    if (new_brk < brk_page) {
     73        target_brk = new_brk;
     74        return 0;
     75    }
     76
     77    /* We need to allocate more memory after the brk... */
     78    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
     79    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
     80                                        PROT_READ|PROT_WRITE,
     81                                        MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0));
     82
     83    if (!is_error(mapped_addr))
     84        target_brk = new_brk;
     85    else
     86        return mapped_addr;
     87
     88    return 0;
     89}
     90
     91#if defined(TARGET_I386)
     92static abi_long do_freebsd_sysarch(CPUX86State *env, int op, abi_ulong parms)
     93{
     94    abi_long ret = 0;
     95    abi_ulong val;
     96    int idx;
     97
     98    switch (op) {
     99#ifdef TARGET_ABI32
    100    case TARGET_FREEBSD_I386_SET_GSBASE:
    101    case TARGET_FREEBSD_I386_SET_FSBASE:
    102        if (op == TARGET_FREEBSD_I386_SET_GSBASE)
    103#else
    104    case TARGET_FREEBSD_AMD64_SET_GSBASE:
    105    case TARGET_FREEBSD_AMD64_SET_FSBASE:
    106        if (op == TARGET_FREEBSD_AMD64_SET_GSBASE)
    107#endif
    108            idx = R_GS;
    109        else
    110            idx = R_FS;
    111        if (get_user(val, parms, abi_ulong))
    112            return -TARGET_EFAULT;
    113        cpu_x86_load_seg(env, idx, 0);
    114        env->segs[idx].base = val;
    115        break;
    116#ifdef TARGET_ABI32
    117    case TARGET_FREEBSD_I386_GET_GSBASE:
    118    case TARGET_FREEBSD_I386_GET_FSBASE:
    119        if (op == TARGET_FREEBSD_I386_GET_GSBASE)
    120#else
    121    case TARGET_FREEBSD_AMD64_GET_GSBASE:
    122    case TARGET_FREEBSD_AMD64_GET_FSBASE:
    123        if (op == TARGET_FREEBSD_AMD64_GET_GSBASE)
    124#endif
    125            idx = R_GS;
    126        else
    127            idx = R_FS;
    128        val = env->segs[idx].base;
    129        if (put_user(val, parms, abi_ulong))
    130            return -TARGET_EFAULT;
    131        break;
    132    /* XXX handle the others... */
    133    default:
    134        ret = -TARGET_EINVAL;
    135        break;
    136    }
    137    return ret;
    138}
    139#endif
    140
    141#ifdef __FreeBSD__
    142/*
    143 * XXX this uses the undocumented oidfmt interface to find the kind of
    144 * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt()
    145 * (this is mostly copied from src/sbin/sysctl/sysctl.c)
    146 */
    147static int
    148oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
    149{
    150    int qoid[CTL_MAXNAME+2];
    151    uint8_t buf[BUFSIZ];
    152    int i;
    153    size_t j;
    154
    155    qoid[0] = 0;
    156    qoid[1] = 4;
    157    memcpy(qoid + 2, oid, len * sizeof(int));
    158
    159    j = sizeof(buf);
    160    i = sysctl(qoid, len + 2, buf, &j, 0, 0);
    161    if (i)
    162        return i;
    163
    164    if (kind)
    165        *kind = *(uint32_t *)buf;
    166
    167    if (fmt)
    168        strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
    169    return (0);
    170}
    171
    172/*
    173 * try and convert sysctl return data for the target.
    174 * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT.
    175 */
    176static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind)
    177{
    178    switch (kind & CTLTYPE) {
    179    case CTLTYPE_INT:
    180    case CTLTYPE_UINT:
    181        *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp);
    182        break;
    183#ifdef TARGET_ABI32
    184    case CTLTYPE_LONG:
    185    case CTLTYPE_ULONG:
    186        *(uint32_t *)holdp = tswap32(*(long *)holdp);
    187        break;
    188#else
    189    case CTLTYPE_LONG:
    190        *(uint64_t *)holdp = tswap64(*(long *)holdp);
    191        break;
    192    case CTLTYPE_ULONG:
    193        *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp);
    194        break;
    195#endif
    196#ifdef CTLTYPE_U64
    197    case CTLTYPE_S64:
    198    case CTLTYPE_U64:
    199#else
    200    case CTLTYPE_QUAD:
    201#endif
    202        *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp);
    203        break;
    204    case CTLTYPE_STRING:
    205        break;
    206    default:
    207        /* XXX unhandled */
    208        return -1;
    209    }
    210    return 0;
    211}
    212
    213/* XXX this needs to be emulated on non-FreeBSD hosts... */
    214static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong oldp,
    215                          abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
    216{
    217    abi_long ret;
    218    void *hnamep, *holdp, *hnewp = NULL;
    219    size_t holdlen;
    220    abi_ulong oldlen = 0;
    221    int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i;
    222    uint32_t kind = 0;
    223
    224    if (oldlenp)
    225        get_user_ual(oldlen, oldlenp);
    226    if (!(hnamep = lock_user(VERIFY_READ, namep, namelen, 1)))
    227        return -TARGET_EFAULT;
    228    if (newp && !(hnewp = lock_user(VERIFY_READ, newp, newlen, 1)))
    229        return -TARGET_EFAULT;
    230    if (!(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0)))
    231        return -TARGET_EFAULT;
    232    holdlen = oldlen;
    233    for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++)
    234       *q++ = tswap32(*p);
    235    oidfmt(snamep, namelen, NULL, &kind);
    236    /* XXX swap hnewp */
    237    ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
    238    if (!ret)
    239        sysctl_oldcvt(holdp, holdlen, kind);
    240    put_user_ual(holdlen, oldlenp);
    241    unlock_user(hnamep, namep, 0);
    242    unlock_user(holdp, oldp, holdlen);
    243    if (hnewp)
    244        unlock_user(hnewp, newp, 0);
    245    g_free(snamep);
    246    return ret;
    247}
    248#endif
    249
    250/* FIXME
    251 * lock_iovec()/unlock_iovec() have a return code of 0 for success where
    252 * other lock functions have a return code of 0 for failure.
    253 */
    254static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
    255                           int count, int copy)
    256{
    257    struct target_iovec *target_vec;
    258    abi_ulong base;
    259    int i;
    260
    261    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
    262    if (!target_vec)
    263        return -TARGET_EFAULT;
    264    for (i = 0;i < count; i++) {
    265        base = tswapl(target_vec[i].iov_base);
    266        vec[i].iov_len = tswapl(target_vec[i].iov_len);
    267        if (vec[i].iov_len != 0) {
    268            vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
    269            /* Don't check lock_user return value. We must call writev even
    270               if a element has invalid base address. */
    271        } else {
    272            /* zero length pointer is ignored */
    273            vec[i].iov_base = NULL;
    274        }
    275    }
    276    unlock_user (target_vec, target_addr, 0);
    277    return 0;
    278}
    279
    280static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
    281                             int count, int copy)
    282{
    283    struct target_iovec *target_vec;
    284    abi_ulong base;
    285    int i;
    286
    287    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
    288    if (!target_vec)
    289        return -TARGET_EFAULT;
    290    for (i = 0;i < count; i++) {
    291        if (target_vec[i].iov_base) {
    292            base = tswapl(target_vec[i].iov_base);
    293            unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
    294        }
    295    }
    296    unlock_user (target_vec, target_addr, 0);
    297
    298    return 0;
    299}
    300
    301/* do_syscall() should always have a single exit point at the end so
    302   that actions, such as logging of syscall results, can be performed.
    303   All errnos that do_syscall() returns must be -TARGET_<errcode>. */
    304abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
    305                            abi_long arg2, abi_long arg3, abi_long arg4,
    306                            abi_long arg5, abi_long arg6, abi_long arg7,
    307                            abi_long arg8)
    308{
    309    CPUState *cpu = env_cpu(cpu_env);
    310    abi_long ret;
    311    void *p;
    312
    313#ifdef DEBUG
    314    gemu_log("freebsd syscall %d\n", num);
    315#endif
    316    record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
    317
    318    if (do_strace)
    319        print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
    320
    321    switch (num) {
    322    case TARGET_FREEBSD_NR_exit:
    323#ifdef CONFIG_GPROF
    324        _mcleanup();
    325#endif
    326        gdb_exit(arg1);
    327        qemu_plugin_user_exit();
    328        /* XXX: should free thread stack and CPU env */
    329        _exit(arg1);
    330        ret = 0; /* avoid warning */
    331        break;
    332    case TARGET_FREEBSD_NR_read:
    333        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
    334            goto efault;
    335        ret = get_errno(read(arg1, p, arg3));
    336        unlock_user(p, arg2, ret);
    337        break;
    338    case TARGET_FREEBSD_NR_write:
    339        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
    340            goto efault;
    341        ret = get_errno(write(arg1, p, arg3));
    342        unlock_user(p, arg2, 0);
    343        break;
    344    case TARGET_FREEBSD_NR_writev:
    345        {
    346            int count = arg3;
    347            struct iovec *vec;
    348
    349            vec = alloca(count * sizeof(struct iovec));
    350            if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
    351                goto efault;
    352            ret = get_errno(writev(arg1, vec, count));
    353            unlock_iovec(vec, arg2, count, 0);
    354        }
    355        break;
    356    case TARGET_FREEBSD_NR_open:
    357        if (!(p = lock_user_string(arg1)))
    358            goto efault;
    359        ret = get_errno(open(path(p),
    360                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
    361                             arg3));
    362        unlock_user(p, arg1, 0);
    363        break;
    364    case TARGET_FREEBSD_NR_mmap:
    365        ret = get_errno(target_mmap(arg1, arg2, arg3,
    366                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
    367                                    arg5,
    368                                    arg6));
    369        break;
    370    case TARGET_FREEBSD_NR_mprotect:
    371        ret = get_errno(target_mprotect(arg1, arg2, arg3));
    372        break;
    373    case TARGET_FREEBSD_NR_break:
    374        ret = do_obreak(arg1);
    375        break;
    376#ifdef __FreeBSD__
    377    case TARGET_FREEBSD_NR___sysctl:
    378        ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6);
    379        break;
    380#endif
    381    case TARGET_FREEBSD_NR_sysarch:
    382        ret = do_freebsd_sysarch(cpu_env, arg1, arg2);
    383        break;
    384    case TARGET_FREEBSD_NR_syscall:
    385    case TARGET_FREEBSD_NR___syscall:
    386        ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0);
    387        break;
    388    default:
    389        ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
    390        break;
    391    }
    392 fail:
    393#ifdef DEBUG
    394    gemu_log(" = %ld\n", ret);
    395#endif
    396    if (do_strace)
    397        print_freebsd_syscall_ret(num, ret);
    398
    399    record_syscall_return(cpu, num, ret);
    400    return ret;
    401 efault:
    402    ret = -TARGET_EFAULT;
    403    goto fail;
    404}
    405
    406abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
    407                           abi_long arg2, abi_long arg3, abi_long arg4,
    408                           abi_long arg5, abi_long arg6)
    409{
    410    CPUState *cpu = env_cpu(cpu_env);
    411    abi_long ret;
    412    void *p;
    413
    414#ifdef DEBUG
    415    gemu_log("netbsd syscall %d\n", num);
    416#endif
    417
    418    record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
    419
    420    if (do_strace)
    421        print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
    422
    423    switch (num) {
    424    case TARGET_NETBSD_NR_exit:
    425#ifdef CONFIG_GPROF
    426        _mcleanup();
    427#endif
    428        gdb_exit(arg1);
    429        qemu_plugin_user_exit();
    430        /* XXX: should free thread stack and CPU env */
    431        _exit(arg1);
    432        ret = 0; /* avoid warning */
    433        break;
    434    case TARGET_NETBSD_NR_read:
    435        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
    436            goto efault;
    437        ret = get_errno(read(arg1, p, arg3));
    438        unlock_user(p, arg2, ret);
    439        break;
    440    case TARGET_NETBSD_NR_write:
    441        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
    442            goto efault;
    443        ret = get_errno(write(arg1, p, arg3));
    444        unlock_user(p, arg2, 0);
    445        break;
    446    case TARGET_NETBSD_NR_open:
    447        if (!(p = lock_user_string(arg1)))
    448            goto efault;
    449        ret = get_errno(open(path(p),
    450                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
    451                             arg3));
    452        unlock_user(p, arg1, 0);
    453        break;
    454    case TARGET_NETBSD_NR_mmap:
    455        ret = get_errno(target_mmap(arg1, arg2, arg3,
    456                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
    457                                    arg5,
    458                                    arg6));
    459        break;
    460    case TARGET_NETBSD_NR_mprotect:
    461        ret = get_errno(target_mprotect(arg1, arg2, arg3));
    462        break;
    463    case TARGET_NETBSD_NR_syscall:
    464    case TARGET_NETBSD_NR___syscall:
    465        ret = do_netbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
    466        break;
    467    default:
    468        ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
    469        break;
    470    }
    471 fail:
    472#ifdef DEBUG
    473    gemu_log(" = %ld\n", ret);
    474#endif
    475    if (do_strace)
    476        print_netbsd_syscall_ret(num, ret);
    477
    478    record_syscall_return(cpu, num, ret);
    479    return ret;
    480 efault:
    481    ret = -TARGET_EFAULT;
    482    goto fail;
    483}
    484
    485abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
    486                            abi_long arg2, abi_long arg3, abi_long arg4,
    487                            abi_long arg5, abi_long arg6)
    488{
    489    CPUState *cpu = env_cpu(cpu_env);
    490    abi_long ret;
    491    void *p;
    492
    493#ifdef DEBUG
    494    gemu_log("openbsd syscall %d\n", num);
    495#endif
    496
    497    record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
    498
    499    if (do_strace)
    500        print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
    501
    502    switch (num) {
    503    case TARGET_OPENBSD_NR_exit:
    504#ifdef CONFIG_GPROF
    505        _mcleanup();
    506#endif
    507        gdb_exit(arg1);
    508        qemu_plugin_user_exit();
    509        /* XXX: should free thread stack and CPU env */
    510        _exit(arg1);
    511        ret = 0; /* avoid warning */
    512        break;
    513    case TARGET_OPENBSD_NR_read:
    514        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
    515            goto efault;
    516        ret = get_errno(read(arg1, p, arg3));
    517        unlock_user(p, arg2, ret);
    518        break;
    519    case TARGET_OPENBSD_NR_write:
    520        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
    521            goto efault;
    522        ret = get_errno(write(arg1, p, arg3));
    523        unlock_user(p, arg2, 0);
    524        break;
    525    case TARGET_OPENBSD_NR_open:
    526        if (!(p = lock_user_string(arg1)))
    527            goto efault;
    528        ret = get_errno(open(path(p),
    529                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
    530                             arg3));
    531        unlock_user(p, arg1, 0);
    532        break;
    533    case TARGET_OPENBSD_NR_mmap:
    534        ret = get_errno(target_mmap(arg1, arg2, arg3,
    535                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
    536                                    arg5,
    537                                    arg6));
    538        break;
    539    case TARGET_OPENBSD_NR_mprotect:
    540        ret = get_errno(target_mprotect(arg1, arg2, arg3));
    541        break;
    542    case TARGET_OPENBSD_NR_syscall:
    543    case TARGET_OPENBSD_NR___syscall:
    544        ret = do_openbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
    545        break;
    546    default:
    547        ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
    548        break;
    549    }
    550 fail:
    551#ifdef DEBUG
    552    gemu_log(" = %ld\n", ret);
    553#endif
    554    if (do_strace)
    555        print_openbsd_syscall_ret(num, ret);
    556
    557    record_syscall_return(cpu, num, ret);
    558    return ret;
    559 efault:
    560    ret = -TARGET_EFAULT;
    561    goto fail;
    562}
    563
    564void syscall_init(void)
    565{
    566}