Commit c077a998 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/riku/tags/pull-linux-user-20170531' into staging



Misc linux-user updates

# gpg: Signature made Wed 31 May 2017 12:33:17 BST
# gpg:                using RSA key 0xB44890DEDE3C9BC0
# gpg: Good signature from "Riku Voipio <riku.voipio@iki.fi>"
# gpg:                 aka "Riku Voipio <riku.voipio@linaro.org>"
# Primary key fingerprint: FF82 03C8 C391 98AE 0581  41EF B448 90DE DE3C 9BC0

* remotes/riku/tags/pull-linux-user-20170531:
  linux-user: add strace support for uinfo structure of rt_sigqueueinfo() and rt_tgsigqueueinfo()
  linux-user: fix inconsistent spaces in print_siginfo() output
  linux-user: add rt_tgsigqueueinfo() strace
  linux-user: add support for rt_tgsigqueueinfo() system call
  linux-user: fix argument type declaration of rt_sigqueinfo() syscall
  linux-user: fix mismatch of lock/unlock_user() invocations in rt_sigqueinfo() syscall
  linux-user: fix ssetmask() system call
  linux-user: add tkill(), tgkill() and rt_sigqueueinfo() strace
  linux-user: add strace for getuid(), gettid(), getppid(), geteuid()
  linux-user: remove all traces of qemu from /proc/self/cmdline
  linux-user: allocate heap memory for execve arguments
  linux-user: fix inotify
  linux-user: fix fadvise64_64() on ppc
  linux-user: fix eventfd
  linux-user: call fd_trans_target_to_host_data() for write()

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents e5cac10a ba9fcea1
Loading
Loading
Loading
Loading
+171 −6
Original line number Diff line number Diff line
@@ -188,6 +188,93 @@ static void print_si_code(int arg)
    gemu_log("%s", codename);
}

static void get_target_siginfo(target_siginfo_t *tinfo,
                                const target_siginfo_t *info)
{
    abi_ulong sival_ptr;

    int sig;
    int si_errno;
    int si_code;
    int si_type;

    __get_user(sig, &info->si_signo);
    __get_user(si_errno, &tinfo->si_errno);
    __get_user(si_code, &info->si_code);

    tinfo->si_signo = sig;
    tinfo->si_errno = si_errno;
    tinfo->si_code = si_code;

    /* Ensure we don't leak random junk to the guest later */
    memset(tinfo->_sifields._pad, 0, sizeof(tinfo->_sifields._pad));

    /* This is awkward, because we have to use a combination of
     * the si_code and si_signo to figure out which of the union's
     * members are valid. (Within the host kernel it is always possible
     * to tell, but the kernel carefully avoids giving userspace the
     * high 16 bits of si_code, so we don't have the information to
     * do this the easy way...) We therefore make our best guess,
     * bearing in mind that a guest can spoof most of the si_codes
     * via rt_sigqueueinfo() if it likes.
     *
     * Once we have made our guess, we record it in the top 16 bits of
     * the si_code, so that print_siginfo() later can use it.
     * print_siginfo() will strip these top bits out before printing
     * the si_code.
     */

    switch (si_code) {
    case SI_USER:
    case SI_TKILL:
    case SI_KERNEL:
        /* Sent via kill(), tkill() or tgkill(), or direct from the kernel.
         * These are the only unspoofable si_code values.
         */
        __get_user(tinfo->_sifields._kill._pid, &info->_sifields._kill._pid);
        __get_user(tinfo->_sifields._kill._uid, &info->_sifields._kill._uid);
        si_type = QEMU_SI_KILL;
        break;
    default:
        /* Everything else is spoofable. Make best guess based on signal */
        switch (sig) {
        case TARGET_SIGCHLD:
            __get_user(tinfo->_sifields._sigchld._pid,
                       &info->_sifields._sigchld._pid);
            __get_user(tinfo->_sifields._sigchld._uid,
                       &info->_sifields._sigchld._uid);
            __get_user(tinfo->_sifields._sigchld._status,
                       &info->_sifields._sigchld._status);
            __get_user(tinfo->_sifields._sigchld._utime,
                       &info->_sifields._sigchld._utime);
            __get_user(tinfo->_sifields._sigchld._stime,
                       &info->_sifields._sigchld._stime);
            si_type = QEMU_SI_CHLD;
            break;
        case TARGET_SIGIO:
            __get_user(tinfo->_sifields._sigpoll._band,
                       &info->_sifields._sigpoll._band);
            __get_user(tinfo->_sifields._sigpoll._fd,
                       &info->_sifields._sigpoll._fd);
            si_type = QEMU_SI_POLL;
            break;
        default:
            /* Assume a sigqueue()/mq_notify()/rt_sigqueueinfo() source. */
            __get_user(tinfo->_sifields._rt._pid, &info->_sifields._rt._pid);
            __get_user(tinfo->_sifields._rt._uid, &info->_sifields._rt._uid);
            /* XXX: potential problem if 64 bit */
            __get_user(sival_ptr, &info->_sifields._rt._sigval.sival_ptr);
            tinfo->_sifields._rt._sigval.sival_ptr = sival_ptr;

            si_type = QEMU_SI_RT;
            break;
        }
        break;
    }

    tinfo->si_code = deposit32(si_code, 16, 16, si_type);
}

static void print_siginfo(const target_siginfo_t *tinfo)
{
    /* Print a target_siginfo_t in the format desired for printing
@@ -1901,6 +1988,57 @@ print_rt_sigprocmask(const struct syscallname *name,
}
#endif

#ifdef TARGET_NR_rt_sigqueueinfo
static void
print_rt_sigqueueinfo(const struct syscallname *name,
    abi_long arg0, abi_long arg1, abi_long arg2,
    abi_long arg3, abi_long arg4, abi_long arg5)
{
    void *p;
    target_siginfo_t uinfo;

    print_syscall_prologue(name);
    print_raw_param("%d", arg0, 0);
    print_signal(arg1, 0);
    p = lock_user(VERIFY_READ, arg2, sizeof(target_siginfo_t), 1);
    if (p) {
        get_target_siginfo(&uinfo, p);
        print_siginfo(&uinfo);

        unlock_user(p, arg2, 0);
    } else {
        print_pointer(arg2, 1);
    }
    print_syscall_epilogue(name);
}
#endif

#ifdef TARGET_NR_rt_tgsigqueueinfo
static void
print_rt_tgsigqueueinfo(const struct syscallname *name,
    abi_long arg0, abi_long arg1, abi_long arg2,
    abi_long arg3, abi_long arg4, abi_long arg5)
{
    void *p;
    target_siginfo_t uinfo;

    print_syscall_prologue(name);
    print_raw_param("%d", arg0, 0);
    print_raw_param("%d", arg1, 0);
    print_signal(arg2, 0);
    p = lock_user(VERIFY_READ, arg3, sizeof(target_siginfo_t), 1);
    if (p) {
        get_target_siginfo(&uinfo, p);
        print_siginfo(&uinfo);

        unlock_user(p, arg3, 0);
    } else {
        print_pointer(arg3, 1);
    }
    print_syscall_epilogue(name);
}
#endif

#ifdef TARGET_NR_syslog
static void
print_syslog_action(abi_ulong arg, int last)
@@ -2415,6 +2553,33 @@ print_kill(const struct syscallname *name,
}
#endif

#ifdef TARGET_NR_tkill
static void
print_tkill(const struct syscallname *name,
    abi_long arg0, abi_long arg1, abi_long arg2,
    abi_long arg3, abi_long arg4, abi_long arg5)
{
    print_syscall_prologue(name);
    print_raw_param("%d", arg0, 0);
    print_signal(arg1, 1);
    print_syscall_epilogue(name);
}
#endif

#ifdef TARGET_NR_tgkill
static void
print_tgkill(const struct syscallname *name,
    abi_long arg0, abi_long arg1, abi_long arg2,
    abi_long arg3, abi_long arg4, abi_long arg5)
{
    print_syscall_prologue(name);
    print_raw_param("%d", arg0, 0);
    print_raw_param("%d", arg1, 0);
    print_signal(arg2, 1);
    print_syscall_epilogue(name);
}
#endif

/*
 * An array of all of the syscalls we know about
 */
+8 −8
Original line number Diff line number Diff line
@@ -290,7 +290,7 @@
{ TARGET_NR_getegid32, "getegid32" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_geteuid
{ TARGET_NR_geteuid, "geteuid" , NULL, NULL, NULL },
{ TARGET_NR_geteuid, "geteuid" , "%s()", NULL, NULL },
#endif
#ifdef TARGET_NR_geteuid32
{ TARGET_NR_geteuid32, "geteuid32" , NULL, NULL, NULL },
@@ -338,7 +338,7 @@
{ TARGET_NR_getpmsg, "getpmsg" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_getppid
{ TARGET_NR_getppid, "getppid" , NULL, NULL, NULL },
{ TARGET_NR_getppid, "getppid" , "%s()", NULL, NULL },
#endif
#ifdef TARGET_NR_getpriority
{ TARGET_NR_getpriority, "getpriority", "%s(%#x,%#x)", NULL, NULL },
@@ -381,13 +381,13 @@
  NULL, NULL },
#endif
#ifdef TARGET_NR_gettid
{ TARGET_NR_gettid, "gettid" , NULL, NULL, NULL },
{ TARGET_NR_gettid, "gettid" , "%s()", NULL, NULL },
#endif
#ifdef TARGET_NR_gettimeofday
{ TARGET_NR_gettimeofday, "gettimeofday" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_getuid
{ TARGET_NR_getuid, "getuid" , NULL, NULL, NULL },
{ TARGET_NR_getuid, "getuid" , "%s()", NULL, NULL },
#endif
#ifdef TARGET_NR_getuid32
{ TARGET_NR_getuid32, "getuid32" , NULL, NULL, NULL },
@@ -1155,7 +1155,7 @@
{ TARGET_NR_rt_sigprocmask, "rt_sigprocmask" , NULL, print_rt_sigprocmask, NULL },
#endif
#ifdef TARGET_NR_rt_sigqueueinfo
{ TARGET_NR_rt_sigqueueinfo, "rt_sigqueueinfo" , NULL, NULL, NULL },
{ TARGET_NR_rt_sigqueueinfo, "rt_sigqueueinfo" , NULL, print_rt_sigqueueinfo, NULL },
#endif
#ifdef TARGET_NR_rt_sigreturn
{ TARGET_NR_rt_sigreturn, "rt_sigreturn" , NULL, NULL, NULL },
@@ -1167,7 +1167,7 @@
{ TARGET_NR_rt_sigtimedwait, "rt_sigtimedwait" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_rt_tgsigqueueinfo
{ TARGET_NR_rt_tgsigqueueinfo, "rt_tgsigqueueinfo" , NULL, NULL, NULL },
{ TARGET_NR_rt_tgsigqueueinfo, "rt_tgsigqueueinfo" , NULL, print_rt_tgsigqueueinfo, NULL },
#endif
#ifdef TARGET_NR_sched_getaffinity
{ TARGET_NR_sched_getaffinity, "sched_getaffinity" , NULL, NULL, NULL },
@@ -1498,7 +1498,7 @@
{ TARGET_NR_tee, "tee" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_tgkill
{ TARGET_NR_tgkill, "tgkill" , NULL, NULL, NULL },
{ TARGET_NR_tgkill, "tgkill" , NULL, print_tgkill, NULL },
#endif
#ifdef TARGET_NR_time
{ TARGET_NR_time, "time" , NULL, NULL, NULL },
@@ -1534,7 +1534,7 @@
{ TARGET_NR_times, "times" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_tkill
{ TARGET_NR_tkill, "tkill" , NULL, NULL, NULL },
{ TARGET_NR_tkill, "tkill" , NULL, print_tkill, NULL },
#endif
#ifdef TARGET_NR_truncate
{ TARGET_NR_truncate, "truncate" , NULL, NULL, NULL },
+105 −56
Original line number Diff line number Diff line
@@ -238,6 +238,7 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
#define __NR_sys_getdents64 __NR_getdents64
#define __NR_sys_getpriority __NR_getpriority
#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
#define __NR_sys_rt_tgsigqueueinfo __NR_rt_tgsigqueueinfo
#define __NR_sys_syslog __NR_syslog
#define __NR_sys_futex __NR_futex
#define __NR_sys_inotify_init __NR_inotify_init
@@ -274,7 +275,9 @@ _syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, co
_syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
          loff_t *, res, uint, wh);
#endif
_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
_syscall3(int, sys_rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t *, uinfo)
_syscall4(int, sys_rt_tgsigqueueinfo, pid_t, pid, pid_t, tid, int, sig,
          siginfo_t *, uinfo)
_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
#ifdef __NR_exit_group
_syscall1(int,exit_group,int,error_code)
@@ -7358,52 +7361,19 @@ int host_to_target_waitstatus(int status)

static int open_self_cmdline(void *cpu_env, int fd)
{
    int fd_orig = -1;
    bool word_skipped = false;

    fd_orig = open("/proc/self/cmdline", O_RDONLY);
    if (fd_orig < 0) {
        return fd_orig;
    }

    while (true) {
        ssize_t nb_read;
        char buf[128];
        char *cp_buf = buf;

        nb_read = read(fd_orig, buf, sizeof(buf));
        if (nb_read < 0) {
            int e = errno;
            fd_orig = close(fd_orig);
            errno = e;
            return -1;
        } else if (nb_read == 0) {
            break;
        }
    CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env);
    struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm;
    int i;

        if (!word_skipped) {
            /* Skip the first string, which is the path to qemu-*-static
               instead of the actual command. */
            cp_buf = memchr(buf, 0, nb_read);
            if (cp_buf) {
                /* Null byte found, skip one string */
                cp_buf++;
                nb_read -= cp_buf - buf;
                word_skipped = true;
            }
        }
    for (i = 0; i < bprm->argc; i++) {
        size_t len = strlen(bprm->argv[i]) + 1;

        if (word_skipped) {
            if (write(fd, cp_buf, nb_read) != nb_read) {
                int e = errno;
                close(fd_orig);
                errno = e;
        if (write(fd, bprm->argv[i], len) != len) {
            return -1;
        }
    }
    }

    return close(fd_orig);
    return 0;
}

static int open_self_maps(void *cpu_env, int fd)
@@ -7671,6 +7641,55 @@ static target_timer_t get_timer_id(abi_long arg)
    return timerid;
}

static abi_long swap_data_eventfd(void *buf, size_t len)
{
    uint64_t *counter = buf;
    int i;

    if (len < sizeof(uint64_t)) {
        return -EINVAL;
    }

    for (i = 0; i < len; i += sizeof(uint64_t)) {
        *counter = tswap64(*counter);
        counter++;
    }

    return len;
}

static TargetFdTrans target_eventfd_trans = {
    .host_to_target_data = swap_data_eventfd,
    .target_to_host_data = swap_data_eventfd,
};

#if (defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)) || \
    (defined(CONFIG_INOTIFY1) && defined(TARGET_NR_inotify_init1) && \
     defined(__NR_inotify_init1))
static abi_long host_to_target_data_inotify(void *buf, size_t len)
{
    struct inotify_event *ev;
    int i;
    uint32_t name_len;

    for (i = 0; i < len; i += sizeof(struct inotify_event) + name_len) {
        ev = (struct inotify_event *)((char *)buf + i);
        name_len = ev->len;

        ev->wd = tswap32(ev->wd);
        ev->mask = tswap32(ev->mask);
        ev->cookie = tswap32(ev->cookie);
        ev->len = tswap32(name_len);
    }

    return len;
}

static TargetFdTrans target_inotify_trans = {
    .host_to_target_data = host_to_target_data_inotify,
};
#endif

/* do_syscall() should always have a single exit point at the end so
   that actions, such as logging of syscall results, can be performed.
   All errnos that do_syscall() returns must be -TARGET_<errcode>. */
@@ -7767,7 +7786,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
    case TARGET_NR_write:
        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
            goto efault;
        if (fd_trans_target_to_host_data(arg1)) {
            void *copy = g_malloc(arg3);
            memcpy(copy, p, arg3);
            ret = fd_trans_target_to_host_data(arg1)(copy, arg3);
            if (ret >= 0) {
                ret = get_errno(safe_write(arg1, copy, ret));
            }
            g_free(copy);
        } else {
            ret = get_errno(safe_write(arg1, p, arg3));
        }
        unlock_user(p, arg2, 0);
        break;
#ifdef TARGET_NR_open
@@ -7926,8 +7955,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                envc++;
            }

            argp = alloca((argc + 1) * sizeof(void *));
            envp = alloca((envc + 1) * sizeof(void *));
            argp = g_new0(char *, argc + 1);
            envp = g_new0(char *, envc + 1);

            for (gp = guest_argp, q = argp; gp;
                  gp += sizeof(abi_ulong), q++) {
@@ -7988,6 +8017,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                    break;
                unlock_user(*q, addr, 0);
            }

            g_free(argp);
            g_free(envp);
        }
        break;
    case TARGET_NR_chdir:
@@ -8592,17 +8624,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR_ssetmask /* not on alpha */
    case TARGET_NR_ssetmask:
        {
            sigset_t set, oset, cur_set;
            sigset_t set, oset;
            abi_ulong target_set = arg1;
            /* We only have one word of the new mask so we must read
             * the rest of it with do_sigprocmask() and OR in this word.
             * We are guaranteed that a do_sigprocmask() that only queries
             * the signal mask will not fail.
             */
            ret = do_sigprocmask(0, NULL, &cur_set);
            assert(!ret);
            target_to_host_old_sigset(&set, &target_set);
            sigorset(&set, &set, &cur_set);
            ret = do_sigprocmask(SIG_SETMASK, &set, &oset);
            if (!ret) {
                host_to_target_old_sigset(&target_set, &oset);
@@ -8847,10 +8871,23 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                goto efault;
            }
            target_to_host_siginfo(&uinfo, p);
            unlock_user(p, arg1, 0);
            unlock_user(p, arg3, 0);
            ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
        }
        break;
    case TARGET_NR_rt_tgsigqueueinfo:
        {
            siginfo_t uinfo;

            p = lock_user(VERIFY_READ, arg4, sizeof(target_siginfo_t), 1);
            if (!p) {
                goto efault;
            }
            target_to_host_siginfo(&uinfo, p);
            unlock_user(p, arg4, 0);
            ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, arg3, &uinfo));
        }
        break;
#ifdef TARGET_NR_sigreturn
    case TARGET_NR_sigreturn:
        if (block_signals()) {
@@ -11229,6 +11266,15 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,

#ifdef TARGET_NR_fadvise64_64
    case TARGET_NR_fadvise64_64:
#if defined(TARGET_PPC)
        /* 6 args: fd, advice, offset (high, low), len (high, low) */
        ret = arg2;
        arg2 = arg3;
        arg3 = arg4;
        arg4 = arg5;
        arg5 = arg6;
        arg6 = ret;
#else
        /* 6 args: fd, offset (high, low), len (high, low), advice */
        if (regpairs_aligned(cpu_env)) {
            /* offset is in (3,4), len in (5,6) and advice in 7 */
@@ -11238,6 +11284,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
            arg5 = arg6;
            arg6 = arg7;
        }
#endif
        ret = -host_to_target_errno(posix_fadvise(arg1,
                                                  target_offset64(arg2, arg3),
                                                  target_offset64(arg4, arg5),
@@ -11694,6 +11741,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
    case TARGET_NR_inotify_init:
        ret = get_errno(sys_inotify_init());
        fd_trans_register(ret, &target_inotify_trans);
        break;
#endif
#ifdef CONFIG_INOTIFY1
@@ -11701,6 +11749,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
    case TARGET_NR_inotify_init1:
        ret = get_errno(sys_inotify_init1(target_to_host_bitmask(arg1,
                                          fcntl_flags_tbl)));
        fd_trans_register(ret, &target_inotify_trans);
        break;
#endif
#endif
@@ -11866,7 +11915,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#if defined(TARGET_NR_eventfd)
    case TARGET_NR_eventfd:
        ret = get_errno(eventfd(arg1, 0));
        fd_trans_unregister(ret);
        fd_trans_register(ret, &target_eventfd_trans);
        break;
#endif
#if defined(TARGET_NR_eventfd2)
@@ -11880,7 +11929,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
            host_flags |= O_CLOEXEC;
        }
        ret = get_errno(eventfd(arg1, host_flags));
        fd_trans_unregister(ret);
        fd_trans_register(ret, &target_eventfd_trans);
        break;
    }
#endif