From 04b9bcf911af2b4563b1f1b2e8a103b796dcc9eb Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 1 Mar 2017 10:37:47 +0100 Subject: linux-user: call fd_trans_target_to_host_data() for write() As for sendmsg() or sendto(), we must call the target to host data translator if it is defined. This is needed for eventfd(): the write() syscall allows to add a value to the internal counter, and so, it must be byte-swapped to the host order. Signed-off-by: Laurent Vivier Signed-off-by: Riku Voipio --- linux-user/syscall.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index cec8428589..b2b563e388 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7767,7 +7767,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; - ret = get_errno(safe_write(arg1, p, arg3)); + 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 -- cgit 1.4.1 From 562a20b4ef63bdde6e2e5bac0da02302aeb5299f Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 1 Mar 2017 10:37:48 +0100 Subject: linux-user: fix eventfd When a fd is opened using eventfd(), a read provides a 64bit counter in the host byte order, and a write increase the internal counter by the provided 64bit value. Signed-off-by: Laurent Vivier Signed-off-by: Riku Voipio --- linux-user/syscall.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b2b563e388..2da8426aaa 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7671,6 +7671,28 @@ 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, +}; + /* 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_. */ @@ -11876,7 +11898,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) @@ -11890,7 +11912,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 -- cgit 1.4.1 From 43046b5a074029a9354bb2b772ca1f91320440f5 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 2 Mar 2017 01:11:45 +0100 Subject: linux-user: fix fadvise64_64() on ppc On ppc, advice is arg2, not arg6: long ppc_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low, u32 len_high, u32 len_low) Signed-off-by: Laurent Vivier Signed-off-by: Riku Voipio --- linux-user/syscall.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 2da8426aaa..671b13a23b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -11261,6 +11261,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 */ @@ -11270,6 +11279,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), -- cgit 1.4.1 From c4e316cfb5e3f4b58d5d6fb6cb6c2279a5c3229a Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 2 Mar 2017 01:54:48 +0100 Subject: linux-user: fix inotify MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a fd is opened using inotify_init(), a read provides one or more inotify_event structures: struct inotify_event { int wd; uint32_t mask; uint32_t cookie; uint32_t len; char name[]; }; The integer fields must be byte-swapped to the target endianness. Signed-off-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Riku Voipio --- linux-user/syscall.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 671b13a23b..32aba195c5 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7693,6 +7693,33 @@ static TargetFdTrans target_eventfd_trans = { .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_. */ @@ -11736,6 +11763,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 @@ -11743,6 +11771,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 -- cgit 1.4.1 From b936cb50aacf3cccf5d2363095c6547eb709583a Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Tue, 7 Mar 2017 12:51:47 +0530 Subject: linux-user: allocate heap memory for execve arguments Arguments passed to execve(2) call from user program could be large, allocating stack memory for them via alloca(3) call would lead to bad behaviour. Use 'g_new0' to allocate memory for such arguments. Reported-by: Jann Horn Signed-off-by: Prasad J Pandit Reviewed-by: Eric Blake Signed-off-by: Riku Voipio --- linux-user/syscall.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 32aba195c5..c8f6efc89c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7985,8 +7985,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++) { @@ -8047,6 +8047,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: -- cgit 1.4.1 From 58de8b9684cc7b4b1fb3cd47678a04d6924b28de Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Mon, 20 Mar 2017 12:31:55 +0100 Subject: linux-user: remove all traces of qemu from /proc/self/cmdline Instead of post-processing the real contents use the remembered target argv. That removes all traces of qemu, including command line options, and handles QEMU_ARGV0. Signed-off-by: Andreas Schwab Signed-off-by: Riku Voipio --- linux-user/syscall.c | 47 +++++++---------------------------------------- 1 file changed, 7 insertions(+), 40 deletions(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c8f6efc89c..909dde6de6 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7358,52 +7358,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; - } + CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env); + struct linux_binprm *bprm = ((TaskState *)cpu->opaque)->bprm; + int i; - while (true) { - ssize_t nb_read; - char buf[128]; - char *cp_buf = buf; + for (i = 0; i < bprm->argc; i++) { + size_t len = strlen(bprm->argv[i]) + 1; - nb_read = read(fd_orig, buf, sizeof(buf)); - if (nb_read < 0) { - int e = errno; - fd_orig = close(fd_orig); - errno = e; + if (write(fd, bprm->argv[i], len) != len) { return -1; - } else if (nb_read == 0) { - break; - } - - 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; - } - } - - if (word_skipped) { - if (write(fd, cp_buf, nb_read) != nb_read) { - int e = errno; - close(fd_orig); - errno = e; - return -1; - } } } - return close(fd_orig); + return 0; } static int open_self_maps(void *cpu_env, int fd) -- cgit 1.4.1 From a8617d8c2fa888a37ecb7db6635fb44964505277 Mon Sep 17 00:00:00 2001 From: Miloš Stojanović Date: Mon, 15 May 2017 16:59:43 +0200 Subject: linux-user: fix ssetmask() system call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the ssetmask() system call by removing the invocation of sigorset(). The ssetmask() system call should replace the old signal mask with the new and return the old mask. It shouldn't combine the old and the new mask with sigorset(). Fetching the old mask for sigorset() is also no longer needed. The problem was detected after running LTP test group syscalls for the MIPS EL 32 R2 architecture where the test ssetmask01 failed with exit code 1. The test passes now that the ssetmask() system call is fixed. Signed-off-by: Miloš Stojanović Signed-off-by: Riku Voipio --- linux-user/syscall.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 909dde6de6..93bc6f679e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8621,17 +8621,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); -- cgit 1.4.1 From d8b6d892c66c1b6f505cd5a2576e08deea200e6d Mon Sep 17 00:00:00 2001 From: Miloš Stojanović Date: Mon, 15 May 2017 16:59:44 +0200 Subject: linux-user: fix mismatch of lock/unlock_user() invocations in rt_sigqueinfo() syscall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the unlock_user() argument from arg1 to arg3 to match with lock_user(), since arg3 contains the pointer to the siginfo_t structure. Signed-off-by: Miloš Stojanović Signed-off-by: Riku Voipio --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 93bc6f679e..de85bce167 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8868,7 +8868,7 @@ 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; -- cgit 1.4.1 From c1a402a7ae9ba9c41b4ac7e7ca3e48e4d60eb35a Mon Sep 17 00:00:00 2001 From: Miloš Stojanović Date: Mon, 15 May 2017 16:59:45 +0200 Subject: linux-user: fix argument type declaration of rt_sigqueinfo() syscall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the type of the first argument of rt_sigqueinfo() from int to pid_t in the syscall declaration to match specifications of the system call. Proper spacing is added to satisfy checkpatch.pl. Signed-off-by: Miloš Stojanović Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Riku Voipio --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index de85bce167..3373853bb9 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -274,7 +274,7 @@ _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) _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) #ifdef __NR_exit_group _syscall1(int,exit_group,int,error_code) -- cgit 1.4.1 From cf8b8bfc5049c10f70b3a17f66c7d2698a5dcff5 Mon Sep 17 00:00:00 2001 From: Miloš Stojanović Date: Mon, 15 May 2017 16:59:46 +0200 Subject: linux-user: add support for rt_tgsigqueueinfo() system call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new system call: rt_tgsigqueueinfo(). This system call is similar to rt_sigqueueinfo(), but instead of sending the signal and data to the whole thread group with the ID equal to the argument tgid, it sends it to a single thread within that thread group. The ID of the thread is specified by the tid argument. The implementation is based on the rt_sigqueueinfo() in linux-user mode, where the tid is added as the second argument and the previous second and third argument become arguments three and four, respectively. Signed-off-by: Miloš Stojanović Conflicts: linux-user/syscall.c Signed-off-by: Riku Voipio --- linux-user/syscall.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'linux-user/syscall.c') diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 3373853bb9..925ae11ea6 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -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 @@ -275,6 +276,8 @@ _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh); #endif _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) @@ -8872,6 +8875,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, 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()) { -- cgit 1.4.1