qemu

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

os-syscall.c (15390B)


      1 /*
      2  *  BSD syscalls
      3  *
      4  *  Copyright (c) 2003-2008 Fabrice Bellard
      5  *  Copyright (c) 2013-2014 Stacey D. Son
      6  *
      7  *  This program is free software; you can redistribute it and/or modify
      8  *  it under the terms of the GNU General Public License as published by
      9  *  the Free Software Foundation; either version 2 of the License, or
     10  *  (at your option) any later version.
     11  *
     12  *  This program is distributed in the hope that it will be useful,
     13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  *  GNU General Public License for more details.
     16  *
     17  *  You should have received a copy of the GNU General Public License
     18  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
     19  */
     20 
     21 /*
     22  * We need the FreeBSD "legacy" definitions. Rust needs the FreeBSD 11 system
     23  * calls since it doesn't use libc at all, so we have to emulate that despite
     24  * FreeBSD 11 being EOL'd.
     25  */
     26 #define _WANT_FREEBSD11_STAT
     27 #define _WANT_FREEBSD11_STATFS
     28 #define _WANT_FREEBSD11_DIRENT
     29 #define _WANT_KERNEL_ERRNO
     30 #define _WANT_SEMUN
     31 #include "qemu/osdep.h"
     32 #include "qemu/cutils.h"
     33 #include "qemu/path.h"
     34 #include <sys/syscall.h>
     35 #include <sys/cdefs.h>
     36 #include <sys/param.h>
     37 #include <sys/mount.h>
     38 #include <sys/sysctl.h>
     39 #include <utime.h>
     40 
     41 #include "qemu.h"
     42 #include "signal-common.h"
     43 #include "user/syscall-trace.h"
     44 
     45 #include "bsd-file.h"
     46 #include "bsd-proc.h"
     47 
     48 /* I/O */
     49 safe_syscall3(int, open, const char *, path, int, flags, mode_t, mode);
     50 safe_syscall4(int, openat, int, fd, const char *, path, int, flags, mode_t,
     51     mode);
     52 
     53 safe_syscall3(ssize_t, read, int, fd, void *, buf, size_t, nbytes);
     54 safe_syscall4(ssize_t, pread, int, fd, void *, buf, size_t, nbytes, off_t,
     55     offset);
     56 safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt);
     57 safe_syscall4(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt,
     58     off_t, offset);
     59 
     60 safe_syscall3(ssize_t, write, int, fd, void *, buf, size_t, nbytes);
     61 safe_syscall4(ssize_t, pwrite, int, fd, void *, buf, size_t, nbytes, off_t,
     62     offset);
     63 safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt);
     64 safe_syscall4(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
     65     off_t, offset);
     66 
     67 void target_set_brk(abi_ulong new_brk)
     68 {
     69 }
     70 
     71 /*
     72  * errno conversion.
     73  */
     74 abi_long get_errno(abi_long ret)
     75 {
     76     if (ret == -1) {
     77         return -host_to_target_errno(errno);
     78     } else {
     79         return ret;
     80     }
     81 }
     82 
     83 int host_to_target_errno(int err)
     84 {
     85     /*
     86      * All the BSDs have the property that the error numbers are uniform across
     87      * all architectures for a given BSD, though they may vary between different
     88      * BSDs.
     89      */
     90     return err;
     91 }
     92 
     93 bool is_error(abi_long ret)
     94 {
     95     return (abi_ulong)ret >= (abi_ulong)(-4096);
     96 }
     97 
     98 /*
     99  * Unlocks a iovec. Unlike unlock_iovec, it assumes the tvec array itself is
    100  * already locked from target_addr. It will be unlocked as well as all the iovec
    101  * elements.
    102  */
    103 static void helper_unlock_iovec(struct target_iovec *target_vec,
    104                                 abi_ulong target_addr, struct iovec *vec,
    105                                 int count, int copy)
    106 {
    107     for (int i = 0; i < count; i++) {
    108         abi_ulong base = tswapal(target_vec[i].iov_base);
    109 
    110         if (vec[i].iov_base) {
    111             unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
    112         }
    113     }
    114     unlock_user(target_vec, target_addr, 0);
    115 }
    116 
    117 struct iovec *lock_iovec(int type, abi_ulong target_addr,
    118         int count, int copy)
    119 {
    120     struct target_iovec *target_vec;
    121     struct iovec *vec;
    122     abi_ulong total_len, max_len;
    123     int i;
    124     int err = 0;
    125 
    126     if (count == 0) {
    127         errno = 0;
    128         return NULL;
    129     }
    130     if (count < 0 || count > IOV_MAX) {
    131         errno = EINVAL;
    132         return NULL;
    133     }
    134 
    135     vec = g_try_new0(struct iovec, count);
    136     if (vec == NULL) {
    137         errno = ENOMEM;
    138         return NULL;
    139     }
    140 
    141     target_vec = lock_user(VERIFY_READ, target_addr,
    142                            count * sizeof(struct target_iovec), 1);
    143     if (target_vec == NULL) {
    144         err = EFAULT;
    145         goto fail2;
    146     }
    147 
    148     max_len = 0x7fffffff & MIN(TARGET_PAGE_MASK, PAGE_MASK);
    149     total_len = 0;
    150 
    151     for (i = 0; i < count; i++) {
    152         abi_ulong base = tswapal(target_vec[i].iov_base);
    153         abi_long len = tswapal(target_vec[i].iov_len);
    154 
    155         if (len < 0) {
    156             err = EINVAL;
    157             goto fail;
    158         } else if (len == 0) {
    159             /* Zero length pointer is ignored. */
    160             vec[i].iov_base = 0;
    161         } else {
    162             vec[i].iov_base = lock_user(type, base, len, copy);
    163             /*
    164              * If the first buffer pointer is bad, this is a fault.  But
    165              * subsequent bad buffers will result in a partial write; this is
    166              * realized by filling the vector with null pointers and zero
    167              * lengths.
    168              */
    169             if (!vec[i].iov_base) {
    170                 if (i == 0) {
    171                     err = EFAULT;
    172                     goto fail;
    173                 } else {
    174                     /*
    175                      * Fail all the subsequent addresses, they are already
    176                      * zero'd.
    177                      */
    178                     goto out;
    179                 }
    180             }
    181             if (len > max_len - total_len) {
    182                 len = max_len - total_len;
    183             }
    184         }
    185         vec[i].iov_len = len;
    186         total_len += len;
    187     }
    188 out:
    189     unlock_user(target_vec, target_addr, 0);
    190     return vec;
    191 
    192 fail:
    193     helper_unlock_iovec(target_vec, target_addr, vec, i, copy);
    194 fail2:
    195     g_free(vec);
    196     errno = err;
    197     return NULL;
    198 }
    199 
    200 void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
    201         int count, int copy)
    202 {
    203     struct target_iovec *target_vec;
    204 
    205     target_vec = lock_user(VERIFY_READ, target_addr,
    206                            count * sizeof(struct target_iovec), 1);
    207     if (target_vec) {
    208         helper_unlock_iovec(target_vec, target_addr, vec, count, copy);
    209     }
    210 
    211     g_free(vec);
    212 }
    213 
    214 /*
    215  * All errnos that freebsd_syscall() returns must be -TARGET_<errcode>.
    216  */
    217 static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
    218                                 abi_long arg2, abi_long arg3, abi_long arg4,
    219                                 abi_long arg5, abi_long arg6, abi_long arg7,
    220                                 abi_long arg8)
    221 {
    222     abi_long ret;
    223 
    224     switch (num) {
    225         /*
    226          * process system calls
    227          */
    228     case TARGET_FREEBSD_NR_exit: /* exit(2) */
    229         ret = do_bsd_exit(cpu_env, arg1);
    230         break;
    231 
    232         /*
    233          * File system calls.
    234          */
    235     case TARGET_FREEBSD_NR_read: /* read(2) */
    236         ret = do_bsd_read(arg1, arg2, arg3);
    237         break;
    238 
    239     case TARGET_FREEBSD_NR_pread: /* pread(2) */
    240         ret = do_bsd_pread(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
    241         break;
    242 
    243     case TARGET_FREEBSD_NR_readv: /* readv(2) */
    244         ret = do_bsd_readv(arg1, arg2, arg3);
    245         break;
    246 
    247     case TARGET_FREEBSD_NR_preadv: /* preadv(2) */
    248         ret = do_bsd_preadv(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
    249 
    250     case TARGET_FREEBSD_NR_write: /* write(2) */
    251         ret = do_bsd_write(arg1, arg2, arg3);
    252         break;
    253 
    254     case TARGET_FREEBSD_NR_pwrite: /* pwrite(2) */
    255         ret = do_bsd_pwrite(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
    256         break;
    257 
    258     case TARGET_FREEBSD_NR_writev: /* writev(2) */
    259         ret = do_bsd_writev(arg1, arg2, arg3);
    260         break;
    261 
    262     case TARGET_FREEBSD_NR_pwritev: /* pwritev(2) */
    263         ret = do_bsd_pwritev(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
    264         break;
    265 
    266     case TARGET_FREEBSD_NR_open: /* open(2) */
    267         ret = do_bsd_open(arg1, arg2, arg3);
    268         break;
    269 
    270     case TARGET_FREEBSD_NR_openat: /* openat(2) */
    271         ret = do_bsd_openat(arg1, arg2, arg3, arg4);
    272         break;
    273 
    274     case TARGET_FREEBSD_NR_close: /* close(2) */
    275         ret = do_bsd_close(arg1);
    276         break;
    277 
    278     case TARGET_FREEBSD_NR_fdatasync: /* fdatasync(2) */
    279         ret = do_bsd_fdatasync(arg1);
    280         break;
    281 
    282     case TARGET_FREEBSD_NR_fsync: /* fsync(2) */
    283         ret = do_bsd_fsync(arg1);
    284         break;
    285 
    286     case TARGET_FREEBSD_NR_freebsd12_closefrom: /* closefrom(2) */
    287         ret = do_bsd_closefrom(arg1);
    288         break;
    289 
    290     case TARGET_FREEBSD_NR_revoke: /* revoke(2) */
    291         ret = do_bsd_revoke(arg1);
    292         break;
    293 
    294     case TARGET_FREEBSD_NR_access: /* access(2) */
    295         ret = do_bsd_access(arg1, arg2);
    296         break;
    297 
    298     case TARGET_FREEBSD_NR_eaccess: /* eaccess(2) */
    299         ret = do_bsd_eaccess(arg1, arg2);
    300         break;
    301 
    302     case TARGET_FREEBSD_NR_faccessat: /* faccessat(2) */
    303         ret = do_bsd_faccessat(arg1, arg2, arg3, arg4);
    304         break;
    305 
    306     case TARGET_FREEBSD_NR_chdir: /* chdir(2) */
    307         ret = do_bsd_chdir(arg1);
    308         break;
    309 
    310     case TARGET_FREEBSD_NR_fchdir: /* fchdir(2) */
    311         ret = do_bsd_fchdir(arg1);
    312         break;
    313 
    314     case TARGET_FREEBSD_NR_rename: /* rename(2) */
    315         ret = do_bsd_rename(arg1, arg2);
    316         break;
    317 
    318     case TARGET_FREEBSD_NR_renameat: /* renameat(2) */
    319         ret = do_bsd_renameat(arg1, arg2, arg3, arg4);
    320         break;
    321 
    322     case TARGET_FREEBSD_NR_link: /* link(2) */
    323         ret = do_bsd_link(arg1, arg2);
    324         break;
    325 
    326     case TARGET_FREEBSD_NR_linkat: /* linkat(2) */
    327         ret = do_bsd_linkat(arg1, arg2, arg3, arg4, arg5);
    328         break;
    329 
    330     case TARGET_FREEBSD_NR_unlink: /* unlink(2) */
    331         ret = do_bsd_unlink(arg1);
    332         break;
    333 
    334     case TARGET_FREEBSD_NR_unlinkat: /* unlinkat(2) */
    335         ret = do_bsd_unlinkat(arg1, arg2, arg3);
    336         break;
    337 
    338     case TARGET_FREEBSD_NR_mkdir: /* mkdir(2) */
    339         ret = do_bsd_mkdir(arg1, arg2);
    340         break;
    341 
    342     case TARGET_FREEBSD_NR_mkdirat: /* mkdirat(2) */
    343         ret = do_bsd_mkdirat(arg1, arg2, arg3);
    344         break;
    345 
    346     case TARGET_FREEBSD_NR_rmdir: /* rmdir(2) (XXX no rmdirat()?) */
    347         ret = do_bsd_rmdir(arg1);
    348         break;
    349 
    350     case TARGET_FREEBSD_NR___getcwd: /* undocumented __getcwd() */
    351         ret = do_bsd___getcwd(arg1, arg2);
    352         break;
    353 
    354     case TARGET_FREEBSD_NR_dup: /* dup(2) */
    355         ret = do_bsd_dup(arg1);
    356         break;
    357 
    358     case TARGET_FREEBSD_NR_dup2: /* dup2(2) */
    359         ret = do_bsd_dup2(arg1, arg2);
    360         break;
    361 
    362     case TARGET_FREEBSD_NR_truncate: /* truncate(2) */
    363         ret = do_bsd_truncate(cpu_env, arg1, arg2, arg3, arg4);
    364         break;
    365 
    366     case TARGET_FREEBSD_NR_ftruncate: /* ftruncate(2) */
    367         ret = do_bsd_ftruncate(cpu_env, arg1, arg2, arg3, arg4);
    368         break;
    369 
    370     case TARGET_FREEBSD_NR_acct: /* acct(2) */
    371         ret = do_bsd_acct(arg1);
    372         break;
    373 
    374     case TARGET_FREEBSD_NR_sync: /* sync(2) */
    375         ret = do_bsd_sync();
    376         break;
    377 
    378     case TARGET_FREEBSD_NR_mount: /* mount(2) */
    379         ret = do_bsd_mount(arg1, arg2, arg3, arg4);
    380         break;
    381 
    382     case TARGET_FREEBSD_NR_unmount: /* unmount(2) */
    383         ret = do_bsd_unmount(arg1, arg2);
    384         break;
    385 
    386     case TARGET_FREEBSD_NR_nmount: /* nmount(2) */
    387         ret = do_bsd_nmount(arg1, arg2, arg3);
    388         break;
    389 
    390     case TARGET_FREEBSD_NR_symlink: /* symlink(2) */
    391         ret = do_bsd_symlink(arg1, arg2);
    392         break;
    393 
    394     case TARGET_FREEBSD_NR_symlinkat: /* symlinkat(2) */
    395         ret = do_bsd_symlinkat(arg1, arg2, arg3);
    396         break;
    397 
    398     case TARGET_FREEBSD_NR_readlink: /* readlink(2) */
    399         ret = do_bsd_readlink(cpu_env, arg1, arg2, arg3);
    400         break;
    401 
    402     case TARGET_FREEBSD_NR_readlinkat: /* readlinkat(2) */
    403         ret = do_bsd_readlinkat(arg1, arg2, arg3, arg4);
    404         break;
    405 
    406     case TARGET_FREEBSD_NR_chmod: /* chmod(2) */
    407         ret = do_bsd_chmod(arg1, arg2);
    408         break;
    409 
    410     case TARGET_FREEBSD_NR_fchmod: /* fchmod(2) */
    411         ret = do_bsd_fchmod(arg1, arg2);
    412         break;
    413 
    414     case TARGET_FREEBSD_NR_lchmod: /* lchmod(2) */
    415         ret = do_bsd_lchmod(arg1, arg2);
    416         break;
    417 
    418     case TARGET_FREEBSD_NR_fchmodat: /* fchmodat(2) */
    419         ret = do_bsd_fchmodat(arg1, arg2, arg3, arg4);
    420         break;
    421 
    422     case TARGET_FREEBSD_NR_freebsd11_mknod: /* mknod(2) */
    423         ret = do_bsd_freebsd11_mknod(arg1, arg2, arg3);
    424         break;
    425 
    426     case TARGET_FREEBSD_NR_freebsd11_mknodat: /* mknodat(2) */
    427         ret = do_bsd_freebsd11_mknodat(arg1, arg2, arg3, arg4);
    428         break;
    429 
    430     case TARGET_FREEBSD_NR_mknodat: /* mknodat(2) */
    431         ret = do_bsd_mknodat(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
    432         break;
    433 
    434     case TARGET_FREEBSD_NR_chown: /* chown(2) */
    435         ret = do_bsd_chown(arg1, arg2, arg3);
    436         break;
    437 
    438     case TARGET_FREEBSD_NR_fchown: /* fchown(2) */
    439         ret = do_bsd_fchown(arg1, arg2, arg3);
    440         break;
    441 
    442     case TARGET_FREEBSD_NR_lchown: /* lchown(2) */
    443         ret = do_bsd_lchown(arg1, arg2, arg3);
    444         break;
    445 
    446     case TARGET_FREEBSD_NR_fchownat: /* fchownat(2) */
    447         ret = do_bsd_fchownat(arg1, arg2, arg3, arg4, arg5);
    448         break;
    449 
    450     case TARGET_FREEBSD_NR_chflags: /* chflags(2) */
    451         ret = do_bsd_chflags(arg1, arg2);
    452         break;
    453 
    454     case TARGET_FREEBSD_NR_lchflags: /* lchflags(2) */
    455         ret = do_bsd_lchflags(arg1, arg2);
    456         break;
    457 
    458     case TARGET_FREEBSD_NR_fchflags: /* fchflags(2) */
    459         ret = do_bsd_fchflags(arg1, arg2);
    460         break;
    461 
    462     case TARGET_FREEBSD_NR_chroot: /* chroot(2) */
    463         ret = do_bsd_chroot(arg1);
    464         break;
    465 
    466     case TARGET_FREEBSD_NR_flock: /* flock(2) */
    467         ret = do_bsd_flock(arg1, arg2);
    468         break;
    469 
    470     case TARGET_FREEBSD_NR_mkfifo: /* mkfifo(2) */
    471         ret = do_bsd_mkfifo(arg1, arg2);
    472         break;
    473 
    474     case TARGET_FREEBSD_NR_mkfifoat: /* mkfifoat(2) */
    475         ret = do_bsd_mkfifoat(arg1, arg2, arg3);
    476         break;
    477 
    478     case TARGET_FREEBSD_NR_pathconf: /* pathconf(2) */
    479         ret = do_bsd_pathconf(arg1, arg2);
    480         break;
    481 
    482     case TARGET_FREEBSD_NR_lpathconf: /* lpathconf(2) */
    483         ret = do_bsd_lpathconf(arg1, arg2);
    484         break;
    485 
    486     case TARGET_FREEBSD_NR_fpathconf: /* fpathconf(2) */
    487         ret = do_bsd_fpathconf(arg1, arg2);
    488         break;
    489 
    490     case TARGET_FREEBSD_NR_undelete: /* undelete(2) */
    491         ret = do_bsd_undelete(arg1);
    492         break;
    493 
    494     default:
    495         qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
    496         ret = -TARGET_ENOSYS;
    497         break;
    498     }
    499 
    500     return ret;
    501 }
    502 
    503 /*
    504  * do_freebsd_syscall() should always have a single exit point at the end so
    505  * that actions, such as logging of syscall results, can be performed. This
    506  * as a wrapper around freebsd_syscall() so that actually happens. Since
    507  * that is a singleton, modern compilers will inline it anyway...
    508  */
    509 abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
    510                             abi_long arg2, abi_long arg3, abi_long arg4,
    511                             abi_long arg5, abi_long arg6, abi_long arg7,
    512                             abi_long arg8)
    513 {
    514     CPUState *cpu = env_cpu(cpu_env);
    515     int ret;
    516 
    517     trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
    518     if (do_strace) {
    519         print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
    520     }
    521 
    522     ret = freebsd_syscall(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6,
    523                           arg7, arg8);
    524     if (do_strace) {
    525         print_freebsd_syscall_ret(num, ret);
    526     }
    527     trace_guest_user_syscall_ret(cpu, num, ret);
    528 
    529     return ret;
    530 }
    531 
    532 void syscall_init(void)
    533 {
    534 }