From d67f4aaae8379b44b3b51ff07df75f693012983c Mon Sep 17 00:00:00 2001 From: Mikhail Ilyin Date: Tue, 5 Aug 2014 17:33:51 +0400 Subject: [PATCH 01/22] linux-user: /proc/self/maps content Build /proc/self/maps doing a match against guest memory translation table. Output only that map records which are valid for guest memory layout. Signed-off-by: Mikhail Ilyin Signed-off-by: Riku Voipio --- include/exec/cpu-all.h | 2 ++ linux-user/syscall.c | 25 ++++++++++--------------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index f91581fc65..f9d132fc0b 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -198,6 +198,8 @@ extern unsigned long reserved_va; #define RESERVED_VA 0ul #endif +#define GUEST_ADDR_MAX (RESERVED_VA ? RESERVED_VA : \ + (1ul << TARGET_VIRT_ADDR_SPACE_BITS) - 1) #endif /* page related stuff */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index a50229d0d7..c8c2b4c15b 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -5092,10 +5092,8 @@ static int open_self_cmdline(void *cpu_env, int fd) static int open_self_maps(void *cpu_env, int fd) { -#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) CPUState *cpu = ENV_GET_CPU((CPUArchState *)cpu_env); TaskState *ts = cpu->opaque; -#endif FILE *fp; char *line = NULL; size_t len = 0; @@ -5118,13 +5116,18 @@ static int open_self_maps(void *cpu_env, int fd) if ((fields < 10) || (fields > 11)) { continue; } - if (!strncmp(path, "[stack]", 7)) { - continue; - } - if (h2g_valid(min) && h2g_valid(max)) { + if (h2g_valid(min)) { + int flags = page_get_flags(h2g(min)); + max = h2g_valid(max - 1) ? max : (uintptr_t)g2h(GUEST_ADDR_MAX); + if (page_check_range(h2g(min), max - min, flags) == -1) { + continue; + } + if (h2g(min) == ts->info->stack_limit) { + pstrcpy(path, sizeof(path), " [stack]"); + } dprintf(fd, TARGET_ABI_FMT_lx "-" TARGET_ABI_FMT_lx " %c%c%c%c %08" PRIx64 " %02x:%02x %d %s%s\n", - h2g(min), h2g(max), flag_r, flag_w, + h2g(min), h2g(max - 1) + 1, flag_r, flag_w, flag_x, flag_p, offset, dev_maj, dev_min, inode, path[0] ? " " : "", path); } @@ -5133,14 +5136,6 @@ static int open_self_maps(void *cpu_env, int fd) free(line); fclose(fp); -#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) - dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n", - (unsigned long long)ts->info->stack_limit, - (unsigned long long)(ts->info->start_stack + - (TARGET_PAGE_SIZE - 1)) & TARGET_PAGE_MASK, - (unsigned long long)0); -#endif - return 0; } From 0b2effd744471adea1cc82966df8a54fd6afa200 Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Wed, 6 Aug 2014 10:36:37 +0300 Subject: [PATCH 02/22] linux-user: redirect openat calls While Mikhail fixed /proc/self/maps, it was noticed openat calls are not redirected currently. Some archs don't have open at all, so openat needs to be redirected. Fix this by consolidating open/openat code to do_openat - open is implemented using openat(AT_FDCWD, ... ), which according to open(2) man page is identical. Since all targets now have openat, remove the ifdef around sys_openat and openat: case in do_syscall. Cc: Mikhail Ilin Signed-off-by: Riku Voipio --- linux-user/syscall.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index c8c2b4c15b..dd776735b5 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -294,7 +294,6 @@ static int sys_getcwd1(char *buf, size_t size) return strlen(buf)+1; } -#ifdef TARGET_NR_openat static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode) { /* @@ -306,7 +305,6 @@ static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode) } return (openat(dirfd, pathname, flags)); } -#endif #ifdef TARGET_NR_utimensat #ifdef CONFIG_UTIMENSAT @@ -5274,7 +5272,7 @@ static int open_net_route(void *cpu_env, int fd) } #endif -static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) +static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode) { struct fake_open { const char *filename; @@ -5295,7 +5293,7 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) if (is_proc_myself(pathname, "exe")) { int execfd = qemu_getauxval(AT_EXECFD); - return execfd ? execfd : get_errno(open(exec_path, flags, mode)); + return execfd ? execfd : get_errno(sys_openat(dirfd, exec_path, flags, mode)); } for (fake_open = fakes; fake_open->filename; fake_open++) { @@ -5329,7 +5327,7 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode) return fd; } - return get_errno(open(path(pathname), flags, mode)); + return get_errno(sys_openat(dirfd, path(pathname), flags, mode)); } /* do_syscall() should always have a single exit point at the end so @@ -5404,22 +5402,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, case TARGET_NR_open: if (!(p = lock_user_string(arg1))) goto efault; - ret = get_errno(do_open(cpu_env, p, - target_to_host_bitmask(arg2, fcntl_flags_tbl), - arg3)); + ret = get_errno(do_openat(cpu_env, AT_FDCWD, p, + target_to_host_bitmask(arg2, fcntl_flags_tbl), + arg3)); unlock_user(p, arg1, 0); break; -#if defined(TARGET_NR_openat) && defined(__NR_openat) case TARGET_NR_openat: if (!(p = lock_user_string(arg2))) goto efault; - ret = get_errno(sys_openat(arg1, - path(p), - target_to_host_bitmask(arg3, fcntl_flags_tbl), - arg4)); + ret = get_errno(do_openat(cpu_env, arg1, p, + target_to_host_bitmask(arg3, fcntl_flags_tbl), + arg4)); unlock_user(p, arg2, 0); break; -#endif case TARGET_NR_close: ret = get_errno(close(arg1)); break; From 47575997be9e0cae44a4fcaecbd172fec3746c96 Mon Sep 17 00:00:00 2001 From: Jincheng Miao Date: Fri, 8 Aug 2014 11:56:54 +0800 Subject: [PATCH 03/22] linux-user: Fix syscall instruction usermode emulation on X86_64 Currently syscall instruction is buggy on user mode X86_64, the EIP is updated after do_syscall(), that is too late for clone(). Because clone() will create a thread at the env->EIP (the address of syscall insn), and then child thread enters do_syscall() again, that is not expected. Sometimes it is tragic. User mode syscall insn emulation is not used MSR, so the action should be same to INT 0x80. INT 0x80 will update EIP in do_interrupt(), ditto for syscall() for consistency. Signed-off-by: Jincheng Miao Reviewed-by: Richard Henderson Signed-off-by: Riku Voipio --- linux-user/main.c | 1 - target-i386/seg_helper.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index b453a39853..472a16d2db 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -309,7 +309,6 @@ void cpu_loop(CPUX86State *env) env->regs[8], env->regs[9], 0, 0); - env->eip = env->exception_next_eip; break; #endif case EXCP0B_NOSEG: diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index 2d970d0cb9..13eefbac3b 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -1127,8 +1127,8 @@ static void do_interrupt_user(CPUX86State *env, int intno, int is_int, /* Since we emulate only user space, we cannot do more than exiting the emulation with the suitable exception and error - code */ - if (is_int) { + code. So update EIP for INT 0x80 and EXCP_SYSCALL. */ + if (is_int || intno == EXCP_SYSCALL) { env->eip = next_eip; } } From c065976f2bca9b87bc699c5fdeb4d3ff1299b8c4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Sat, 9 Aug 2014 15:42:32 +0100 Subject: [PATCH 04/22] linux-user: Fix conversion of sigevent argument to timer_create There were a number of bugs in the conversion of the sigevent argument to timer_create from target to host format: * signal number not converted from target to host * thread ID not copied across * sigev_value not copied across * we never unlocked the struct when we were done Between them, these problems meant that SIGEV_THREAD_ID timers (and the glibc-implemented SIGEV_THREAD timers which depend on them) didn't work. Fix these problems and clean up the code a little by pulling the struct conversion out into its own function, in line with how we convert various other structs. This allows the test program in bug LP:1042388 to run. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index dd776735b5..fccf9f0a26 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4912,6 +4912,32 @@ static inline abi_long host_to_target_itimerspec(abi_ulong target_addr, return 0; } +static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp, + abi_ulong target_addr) +{ + struct target_sigevent *target_sevp; + + if (!lock_user_struct(VERIFY_READ, target_sevp, target_addr, 1)) { + return -TARGET_EFAULT; + } + + /* This union is awkward on 64 bit systems because it has a 32 bit + * integer and a pointer in it; we follow the conversion approach + * used for handling sigval types in signal.c so the guest should get + * the correct value back even if we did a 64 bit byteswap and it's + * using the 32 bit integer. + */ + host_sevp->sigev_value.sival_ptr = + (void *)(uintptr_t)tswapal(target_sevp->sigev_value.sival_ptr); + host_sevp->sigev_signo = + target_to_host_signal(tswap32(target_sevp->sigev_signo)); + host_sevp->sigev_notify = tswap32(target_sevp->sigev_notify); + host_sevp->_sigev_un._tid = tswap32(target_sevp->_sigev_un._tid); + + unlock_user_struct(target_sevp, target_addr, 1); + return 0; +} + #if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat) static inline abi_long host_to_target_stat64(void *cpu_env, abi_ulong target_addr, @@ -9403,7 +9429,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, /* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */ struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL; - struct target_sigevent *ptarget_sevp; struct target_timer_t *ptarget_timer; int clkid = arg1; @@ -9415,14 +9440,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, timer_t *phtimer = g_posix_timers + timer_index; if (arg2) { - if (!lock_user_struct(VERIFY_READ, ptarget_sevp, arg2, 1)) { - goto efault; - } - - host_sevp.sigev_signo = tswap32(ptarget_sevp->sigev_signo); - host_sevp.sigev_notify = tswap32(ptarget_sevp->sigev_notify); - phost_sevp = &host_sevp; + ret = target_to_host_sigevent(phost_sevp, arg2); + if (ret != 0) { + break; + } } ret = get_errno(timer_create(clkid, phost_sevp, phtimer)); From f17f4989fa193fa8279474c5462289a3cfe69aea Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 8 Aug 2014 09:40:25 +0900 Subject: [PATCH 05/22] linux-user: fix readlink handling with magic exe symlink The current code always returns the length of the path when it should be returning the number of bytes it wrote to the output string. Further, readlink is not supposed to append a NUL byte, but the current snprintf logic will always do just that. Even further, if you pass in a length of 0, you're suppoesd to get back an error (EINVAL), but the current logic just returns 0. Further still, if there was an error reading the symlink, we should not go ahead and try to read the target buffer as it is garbage. Simple test for the first two issues: $ cat test.c int main() { char buf[50]; size_t len; for (len = 0; len < 10; ++len) { memset(buf, '!', sizeof(buf)); ssize_t ret = readlink("/proc/self/exe", buf, len); buf[20] = '\0'; printf("readlink(/proc/self/exe, {%s}, %zu) = %zi\n", buf, len, ret); } return 0; } Now compare the output of the native: $ gcc test.c -o /tmp/x $ /tmp/x $ strace /tmp/x With what qemu does: $ armv7a-cros-linux-gnueabi-gcc test.c -o /tmp/x -static $ qemu-arm /tmp/x $ qemu-arm -strace /tmp/x Signed-off-by: Mike Frysinger Signed-off-by: Riku Voipio --- linux-user/syscall.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index fccf9f0a26..7c108abcf2 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6636,11 +6636,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0); if (!p || !p2) { ret = -TARGET_EFAULT; + } else if (!arg3) { + /* Short circuit this for the magic exe check. */ + ret = -TARGET_EINVAL; } else if (is_proc_myself((const char *)p, "exe")) { char real[PATH_MAX], *temp; temp = realpath(exec_path, real); - ret = temp == NULL ? get_errno(-1) : strlen(real) ; - snprintf((char *)p2, arg3, "%s", real); + /* Return value is # of bytes that we wrote to the buffer. */ + if (temp == NULL) { + ret = get_errno(-1); + } else { + /* Don't worry about sign mismatch as earlier mapping + * logic would have thrown a bad address error. */ + ret = MIN(strlen(real), arg3); + /* We cannot NUL terminate the string. */ + memcpy(p2, real, ret); + } } else { ret = get_errno(readlink(path(p), p2, arg3)); } From 518343413fd311a3d95798b2c1d51853fd8d3c85 Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Sun, 22 Jun 2014 11:25:42 +0100 Subject: [PATCH 06/22] linux-user: support timerfd_{create, gettime, settime} syscalls Adds support for the timerfd_create, timerfd_gettime & timerfd_settime syscalls, allowing use of timerfds by target programs. v2: By Riku - added configure check for timerfd and ifdefs for benefit of old distributions like RHEL5. Signed-off-by: Paul Burton Signed-off-by: Riku Voipio --- configure | 17 ++++++++++++++++ linux-user/strace.list | 9 +++++++++ linux-user/syscall.c | 45 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/configure b/configure index 283c71cb7a..3d0ab1b193 100755 --- a/configure +++ b/configure @@ -3456,6 +3456,20 @@ if compile_prog "" "" ; then sendfile=yes fi +# check for timerfd support (glibc 2.8 and newer) +timerfd=no +cat > $TMPC << EOF +#include + +int main(void) +{ + return(timerfd_create(CLOCK_REALTIME, 0)); +} +EOF +if compile_prog "" "" ; then + timerfd=yes +fi + # Check if tools are available to build documentation. if test "$docs" != "no" ; then if has makeinfo && has pod2man; then @@ -4524,6 +4538,9 @@ fi if test "$sendfile" = "yes" ; then echo "CONFIG_SENDFILE=y" >> $config_host_mak fi +if test "$timerfd" = "yes" ; then + echo "CONFIG_TIMERFD=y" >> $config_host_mak +fi if test "$inotify" = "yes" ; then echo "CONFIG_INOTIFY=y" >> $config_host_mak fi diff --git a/linux-user/strace.list b/linux-user/strace.list index fcb258d348..8de972a6ee 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -1404,6 +1404,15 @@ #ifdef TARGET_NR_timer_settime { TARGET_NR_timer_settime, "timer_settime" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_timerfd_create +{ TARGET_NR_timerfd_create, "timerfd_create" , NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_timerfd_gettime +{ TARGET_NR_timerfd_gettime, "timerfd_gettime" , NULL, NULL, NULL }, +#endif +#ifdef TARGET_NR_timerfd_settime +{ TARGET_NR_timerfd_settime, "timerfd_settime" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_times { TARGET_NR_times, "times" , NULL, NULL, NULL }, #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7c108abcf2..44853d090a 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -58,6 +58,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base, #include #include #include +#include #include #include //#include @@ -9547,6 +9548,50 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } #endif +#if defined(TARGET_NR_timerfd_create) && defined(CONFIG_TIMERFD) + case TARGET_NR_timerfd_create: + ret = get_errno(timerfd_create(arg1, + target_to_host_bitmask(arg2, fcntl_flags_tbl))); + break; +#endif + +#if defined(TARGET_NR_timerfd_gettime) && defined(CONFIG_TIMERFD) + case TARGET_NR_timerfd_gettime: + { + struct itimerspec its_curr; + + ret = get_errno(timerfd_gettime(arg1, &its_curr)); + + if (arg2 && host_to_target_itimerspec(arg2, &its_curr)) { + goto efault; + } + } + break; +#endif + +#if defined(TARGET_NR_timerfd_settime) && defined(CONFIG_TIMERFD) + case TARGET_NR_timerfd_settime: + { + struct itimerspec its_new, its_old, *p_new; + + if (arg3) { + if (target_to_host_itimerspec(&its_new, arg3)) { + goto efault; + } + p_new = &its_new; + } else { + p_new = NULL; + } + + ret = get_errno(timerfd_settime(arg1, arg2, p_new, &its_old)); + + if (arg4 && host_to_target_itimerspec(arg4, &its_old)) { + goto efault; + } + } + break; +#endif + default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); From ab31cda3270994ab7a59a3ed8d44029a52af95a3 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Sun, 22 Jun 2014 11:25:43 +0100 Subject: [PATCH 07/22] linux-user: support ioprio_{get, set} syscalls Add support for the ioprio_get & ioprio_set syscalls, allowing their use by target programs. Signed-off-by: Paul Burton Signed-off-by: Riku Voipio --- linux-user/syscall.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 44853d090a..f1c182bbae 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -252,6 +252,12 @@ _syscall2(int, capget, struct __user_cap_header_struct *, header, struct __user_cap_data_struct *, data); _syscall2(int, capset, struct __user_cap_header_struct *, header, struct __user_cap_data_struct *, data); +#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get) +_syscall2(int, ioprio_get, int, which, int, who) +#endif +#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set) +_syscall3(int, ioprio_set, int, which, int, who, int, ioprio) +#endif static bitmask_transtbl fcntl_flags_tbl[] = { { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, }, @@ -9592,6 +9598,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif +#if defined(TARGET_NR_ioprio_get) && defined(__NR_ioprio_get) + case TARGET_NR_ioprio_get: + ret = get_errno(ioprio_get(arg1, arg2)); + break; +#endif + +#if defined(TARGET_NR_ioprio_set) && defined(__NR_ioprio_set) + case TARGET_NR_ioprio_set: + ret = get_errno(ioprio_set(arg1, arg2, arg3)); + break; +#endif + default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); From 9af5c906d189d8f4aae902d75567639d2a8f4e22 Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Tue, 12 Aug 2014 15:58:57 +0300 Subject: [PATCH 08/22] linux-user: add setns and unshare Add support for the setns and unshare syscalls, trivially passed through to the host. Based on patches by Paul Burton, added configure check. Signed-off-by: Paul Burton Signed-off-by: Riku Voipio --- configure | 20 ++++++++++++++++++++ linux-user/strace.list | 3 +++ linux-user/syscall.c | 11 +++++++++++ 3 files changed, 34 insertions(+) diff --git a/configure b/configure index 3d0ab1b193..c4e47e1ea1 100755 --- a/configure +++ b/configure @@ -3470,6 +3470,23 @@ if compile_prog "" "" ; then timerfd=yes fi +# check for setns and unshare support +setns=no +cat > $TMPC << EOF +#include + +int main(void) +{ + int ret; + ret = setns(0, 0); + ret = unshare(0); + return ret; +} +EOF +if compile_prog "" "" ; then + setns=yes +fi + # Check if tools are available to build documentation. if test "$docs" != "no" ; then if has makeinfo && has pod2man; then @@ -4541,6 +4558,9 @@ fi if test "$timerfd" = "yes" ; then echo "CONFIG_TIMERFD=y" >> $config_host_mak fi +if test "$setns" = "yes" ; then + echo "CONFIG_SETNS=y" >> $config_host_mak +fi if test "$inotify" = "yes" ; then echo "CONFIG_INOTIFY=y" >> $config_host_mak fi diff --git a/linux-user/strace.list b/linux-user/strace.list index 8de972a6ee..aa0cd735cc 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -1185,6 +1185,9 @@ #ifdef TARGET_NR_set_mempolicy { TARGET_NR_set_mempolicy, "set_mempolicy" , NULL, NULL, NULL }, #endif +#ifdef TARGET_NR_setns +{ TARGET_NR_setns, "setns" , NULL, NULL, NULL }, +#endif #ifdef TARGET_NR_setpgid { TARGET_NR_setpgid, "setpgid" , NULL, NULL, NULL }, #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index f1c182bbae..dae10afcb8 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -9610,6 +9610,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, break; #endif +#if defined(TARGET_NR_setns) && defined(CONFIG_SETNS) + case TARGET_NR_setns: + ret = get_errno(setns(arg1, arg2)); + break; +#endif +#if defined(TARGET_NR_unshare) && defined(CONFIG_SETNS) + case TARGET_NR_unshare: + ret = get_errno(unshare(arg1)); + break; +#endif + default: unimplemented: gemu_log("qemu: Unsupported syscall: %d\n", num); From 035273440b4d12c6e8b1cf2787778064355d21e2 Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Tue, 12 Aug 2014 13:53:32 -0500 Subject: [PATCH 09/22] linux-user: PPC64 semid_ds Doesnt Include _unused1 and _unused2 The 64 bit PowerPC platforms eliminate the _unused1 and _unused2 elements of the semid_ds structure from . So eliminate these from the target_semid_ds structure. Signed-off-by: Tom Musta Signed-off-by: Riku Voipio --- linux-user/syscall.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index dae10afcb8..fba7fd28cb 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2424,9 +2424,13 @@ struct target_semid_ds { struct target_ipc_perm sem_perm; abi_ulong sem_otime; +#if !defined(TARGET_PPC64) abi_ulong __unused1; +#endif abi_ulong sem_ctime; +#if !defined(TARGET_PPC64) abi_ulong __unused2; +#endif abi_ulong sem_nsems; abi_ulong __unused3; abi_ulong __unused4; From 5d2fa8ebb4dae0057ed9baab617971dcd5ea493f Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Tue, 12 Aug 2014 13:53:33 -0500 Subject: [PATCH 10/22] linux-user: Dereference Pointer Argument to ipc/semctl Sys Call When the ipc system call is used to wrap a semctl system call, the ptr argument to ipc needs to be dereferenced prior to passing it to the semctl handler. This is because the fourth argument to semctl is a union and not a pointer to a union. Signed-off-by: Tom Musta Signed-off-by: Riku Voipio --- linux-user/syscall.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index fba7fd28cb..08fdd94014 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3140,9 +3140,15 @@ static abi_long do_ipc(unsigned int call, int first, ret = get_errno(semget(first, second, third)); break; - case IPCOP_semctl: - ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr); + case IPCOP_semctl: { + /* The semun argument to semctl is passed by value, so dereference the + * ptr argument. */ + abi_ulong atptr; + get_user_ual(atptr, (abi_ulong)ptr); + ret = do_semctl(first, second, third, + (union target_semun)(abi_ulong) atptr); break; + } case IPCOP_msgget: ret = get_errno(msgget(first, second)); From 5464baecf521d1ca8095604f5a7371443c94226a Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Tue, 12 Aug 2014 13:53:34 -0500 Subject: [PATCH 11/22] linux-user: Properly Handle semun Structure In Cross-Endian Situations The semun union used in the semctl system call contains both an int (val) and pointers. In cross-endian situations on 64 bit targets, the value passed to semctl is an 8 byte (abi_long) value and thus does not have the 4-byte val field in the correct location. In order to rectify this, the other half of the union must be accessed. This is achieved in code by performing a byte swap on the entire 8 byte union, followed by a 4-byte swap of the first half. Also, eliminate an extraneous (dead) line of code that sets target_su.val in the IPC_SET/IPC_GET case. Signed-off-by: Tom Musta Signed-off-by: Riku Voipio --- linux-user/syscall.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 08fdd94014..39ab4c7942 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2652,9 +2652,18 @@ static inline abi_long do_semctl(int semid, int semnum, int cmd, switch( cmd ) { case GETVAL: case SETVAL: - arg.val = tswap32(target_su.val); + /* In 64 bit cross-endian situations, we will erroneously pick up + * the wrong half of the union for the "val" element. To rectify + * this, the entire 8-byte structure is byteswapped, followed by + * a swap of the 4 byte val field. In other cases, the data is + * already in proper host byte order. */ + if (sizeof(target_su.val) != (sizeof(target_su.buf))) { + target_su.buf = tswapal(target_su.buf); + arg.val = tswap32(target_su.val); + } else { + arg.val = target_su.val; + } ret = get_errno(semctl(semid, semnum, cmd, arg)); - target_su.val = tswap32(arg.val); break; case GETALL: case SETALL: From 37ed09560c51465c3b8a659b9d18d43e75726c04 Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Tue, 12 Aug 2014 13:53:35 -0500 Subject: [PATCH 12/22] linux-user: Make ipc syscall's third argument an abi_long For those target ABIs that use the ipc system call (e.g. POWER), the third argument is used in the shmat path as a pointer. It therefore must be declared as an abi_long (versus int) so that the address bits are not lost in truncation. In fact, all arguments to do_ipc should be declared as abit_long. In fact, it makes more sense for all of the arguments to be declaried as abi_long (except call). Signed-off-by: Tom Musta Signed-off-by: Riku Voipio --- linux-user/syscall.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 39ab4c7942..fa8ba8fe7c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3130,8 +3130,8 @@ static inline abi_long do_shmdt(abi_ulong shmaddr) #ifdef TARGET_NR_ipc /* ??? This only works with linear mappings. */ /* do_ipc() must return target values and target errnos. */ -static abi_long do_ipc(unsigned int call, int first, - int second, int third, +static abi_long do_ipc(unsigned int call, abi_long first, + abi_long second, abi_long third, abi_long ptr, abi_long fifth) { int version; @@ -3153,9 +3153,9 @@ static abi_long do_ipc(unsigned int call, int first, /* The semun argument to semctl is passed by value, so dereference the * ptr argument. */ abi_ulong atptr; - get_user_ual(atptr, (abi_ulong)ptr); + get_user_ual(atptr, ptr); ret = do_semctl(first, second, third, - (union target_semun)(abi_ulong) atptr); + (union target_semun) atptr); break; } From b6ce1f6b90903961f66b0aec7be75d6c94560e40 Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Tue, 12 Aug 2014 13:53:36 -0500 Subject: [PATCH 13/22] linux-user: Conditionally Pass Attribute Pointer to mq_open() The mq_open system call takes an optional struct mq_attr pointer argument in the fourth position. This pointer is used when O_CREAT is specified in the flags (second) argument. It may be NULL, in which case the queue is created with implementation defined attributes. Change the code to properly handle the case when NULL is passed in the arg4 position. Signed-off-by: Tom Musta Reviewed-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index fa8ba8fe7c..e754dbb3fa 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -9115,12 +9115,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #if defined(TARGET_NR_mq_open) && defined(__NR_mq_open) case TARGET_NR_mq_open: { - struct mq_attr posix_mq_attr; + struct mq_attr posix_mq_attr, *attrp; p = lock_user_string(arg1 - 1); - if (arg4 != 0) + if (arg4 != 0) { copy_from_user_mq_attr (&posix_mq_attr, arg4); - ret = get_errno(mq_open(p, arg2, arg3, &posix_mq_attr)); + attrp = &posix_mq_attr; + } else { + attrp = 0; + } + ret = get_errno(mq_open(p, arg2, arg3, attrp)); unlock_user (p, arg1, 0); } break; From edcc5f9dc39309d32f4b3737e6b750ae967f5bbd Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Tue, 12 Aug 2014 13:53:37 -0500 Subject: [PATCH 14/22] linux-user: Detect Negative Message Sizes in msgsnd System Call The msgsnd system call takes an argument that describes the message size (msgsz) and is of type size_t. The system call should set errno to EINVAL in the event that a negative message size is passed. Signed-off-by: Tom Musta Reviewed-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e754dbb3fa..2549249a08 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2879,12 +2879,16 @@ struct target_msgbuf { }; static inline abi_long do_msgsnd(int msqid, abi_long msgp, - unsigned int msgsz, int msgflg) + ssize_t msgsz, int msgflg) { struct target_msgbuf *target_mb; struct msgbuf *host_mb; abi_long ret = 0; + if (msgsz < 0) { + return -TARGET_EINVAL; + } + if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) return -TARGET_EFAULT; host_mb = malloc(msgsz+sizeof(long)); From a1d5c5b25d06b68aec76e4b0eb7d8aacb5fbd191 Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Tue, 12 Aug 2014 13:53:38 -0500 Subject: [PATCH 15/22] linux-user: Handle NULL sched_param argument to sched_* The sched_getparam, sched_setparam and sched_setscheduler system calls take a pointer argument to a sched_param structure. When this pointer is null, errno should be set to EINVAL. Signed-off-by: Tom Musta Signed-off-by: Riku Voipio --- linux-user/syscall.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 2549249a08..4424b63c86 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7736,6 +7736,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct sched_param *target_schp; struct sched_param schp; + if (arg2 == 0) { + return -TARGET_EINVAL; + } if (!lock_user_struct(VERIFY_READ, target_schp, arg2, 1)) goto efault; schp.sched_priority = tswap32(target_schp->sched_priority); @@ -7747,6 +7750,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct sched_param *target_schp; struct sched_param schp; + + if (arg2 == 0) { + return -TARGET_EINVAL; + } ret = get_errno(sched_getparam(arg1, &schp)); if (!is_error(ret)) { if (!lock_user_struct(VERIFY_WRITE, target_schp, arg2, 0)) @@ -7760,6 +7767,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, { struct sched_param *target_schp; struct sched_param schp; + if (arg3 == 0) { + return -TARGET_EINVAL; + } if (!lock_user_struct(VERIFY_READ, target_schp, arg3, 1)) goto efault; schp.sched_priority = tswap32(target_schp->sched_priority); From d4290c40a4bf297e9af132be81d51bf796882ff2 Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Tue, 12 Aug 2014 13:53:39 -0500 Subject: [PATCH 16/22] linux-user: Detect fault in sched_rr_get_interval Properly detect a fault when attempting to store into an invalid struct timespec pointer. Signed-off-by: Tom Musta Reviewed-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 4424b63c86..ed32f9723f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7794,7 +7794,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, struct timespec ts; ret = get_errno(sched_rr_get_interval(arg1, &ts)); if (!is_error(ret)) { - host_to_target_timespec(arg2, &ts); + ret = host_to_target_timespec(arg2, &ts); } } break; From 67d6d829cdc4e76f64162e6ba8861ee527987bd5 Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Wed, 13 Aug 2014 14:04:44 -0500 Subject: [PATCH 17/22] linux-user: Move get_ppc64_abi The get_ppc64_abi is used to determine the ELF ABI (i.e. V1 or V2). This routine is currently implemented in the linux-user/elfload.c file but is useful in other scenarios. Move the routine to a more generally available location (linux-user/ppc/target_cpu.h). Signed-off-by: Tom Musta Signed-off-by: Riku Voipio --- linux-user/elfload.c | 9 --------- linux-user/ppc/target_cpu.h | 10 ++++++++++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 60777fecf6..bea803bd13 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -824,8 +824,6 @@ static uint32_t get_elf_hwcap2(void) NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ } while (0) -static inline uint32_t get_ppc64_abi(struct image_info *infop); - static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop) { _regs->gpr[1] = infop->start_stack; @@ -1205,13 +1203,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #include "elf.h" -#ifdef TARGET_PPC -static inline uint32_t get_ppc64_abi(struct image_info *infop) -{ - return infop->elf_flags & EF_PPC64_ABI; -} -#endif - struct exec { unsigned int a_info; /* Use macros N_MAGIC, etc for access */ diff --git a/linux-user/ppc/target_cpu.h b/linux-user/ppc/target_cpu.h index 9cc0c3ba9c..26f4ba297f 100644 --- a/linux-user/ppc/target_cpu.h +++ b/linux-user/ppc/target_cpu.h @@ -38,4 +38,14 @@ static inline void cpu_set_tls(CPUPPCState *env, target_ulong newtls) #endif } +#ifndef EF_PPC64_ABI +#define EF_PPC64_ABI 0x3 +#endif + +static inline uint32_t get_ppc64_abi(struct image_info *infop) +{ + return infop->elf_flags & EF_PPC64_ABI; +} + + #endif From 0903c8be9ee7925863c6c50a2096b6e919be861c Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Tue, 12 Aug 2014 13:53:40 -0500 Subject: [PATCH 18/22] linux-user: Minimum Sig Handler Stack Size for PPC64 ELF V2 The ELF V2 ABI for PPC64 defines MINSIGSTKSZ as 4096 bytes whereas it was 2048 previously. Signed-off-by: Tom Musta Signed-off-by: Riku Voipio --- linux-user/aarch64/syscall.h | 1 + linux-user/alpha/syscall.h | 1 + linux-user/arm/syscall.h | 2 ++ linux-user/cris/syscall.h | 1 + linux-user/i386/syscall.h | 1 + linux-user/m68k/syscall.h | 2 ++ linux-user/microblaze/syscall.h | 1 + linux-user/mips/syscall.h | 1 + linux-user/mips64/syscall.h | 1 + linux-user/openrisc/syscall.h | 2 ++ linux-user/ppc/syscall.h | 2 ++ linux-user/s390x/syscall.h | 1 + linux-user/sh4/syscall.h | 2 ++ linux-user/signal.c | 12 +++++++++++- linux-user/sparc/syscall.h | 1 + linux-user/sparc64/syscall.h | 1 + linux-user/unicore32/syscall.h | 2 ++ linux-user/x86_64/syscall.h | 1 + 18 files changed, 34 insertions(+), 1 deletion(-) diff --git a/linux-user/aarch64/syscall.h b/linux-user/aarch64/syscall.h index 18f44a8a40..d1f48232f3 100644 --- a/linux-user/aarch64/syscall.h +++ b/linux-user/aarch64/syscall.h @@ -8,3 +8,4 @@ struct target_pt_regs { #define UNAME_MACHINE "aarch64" #define UNAME_MINIMUM_RELEASE "3.8.0" #define TARGET_CLONE_BACKWARDS +#define TARGET_MINSIGSTKSZ 2048 diff --git a/linux-user/alpha/syscall.h b/linux-user/alpha/syscall.h index ed13d9a718..3adedeba30 100644 --- a/linux-user/alpha/syscall.h +++ b/linux-user/alpha/syscall.h @@ -252,3 +252,4 @@ struct target_pt_regs { #define TARGET_UAC_NOPRINT 1 #define TARGET_UAC_NOFIX 2 #define TARGET_UAC_SIGBUS 4 +#define TARGET_MINSIGSTKSZ 4096 diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index e0d2cc3e5d..cdadb0ce82 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/syscall.h @@ -44,3 +44,5 @@ struct target_pt_regs { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS + +#define TARGET_MINSIGSTKSZ 2048 diff --git a/linux-user/cris/syscall.h b/linux-user/cris/syscall.h index f5783c0557..a75bcc49ea 100644 --- a/linux-user/cris/syscall.h +++ b/linux-user/cris/syscall.h @@ -39,5 +39,6 @@ struct target_pt_regs { }; #define TARGET_CLONE_BACKWARDS2 +#define TARGET_MINSIGSTKSZ 2048 #endif diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h index 9bfc1ad8f7..acf685622d 100644 --- a/linux-user/i386/syscall.h +++ b/linux-user/i386/syscall.h @@ -147,3 +147,4 @@ struct target_vm86plus_struct { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS +#define TARGET_MINSIGSTKSZ 2048 diff --git a/linux-user/m68k/syscall.h b/linux-user/m68k/syscall.h index 889eaf7323..f8553f8c11 100644 --- a/linux-user/m68k/syscall.h +++ b/linux-user/m68k/syscall.h @@ -18,4 +18,6 @@ struct target_pt_regs { #define UNAME_MACHINE "m68k" #define UNAME_MINIMUM_RELEASE "2.6.32" +#define TARGET_MINSIGSTKSZ 2048 + void do_m68k_simcall(CPUM68KState *, int); diff --git a/linux-user/microblaze/syscall.h b/linux-user/microblaze/syscall.h index 5b5f6b447d..2a5e160b03 100644 --- a/linux-user/microblaze/syscall.h +++ b/linux-user/microblaze/syscall.h @@ -49,5 +49,6 @@ struct target_pt_regs { }; #define TARGET_CLONE_BACKWARDS +#define TARGET_MINSIGSTKSZ 2048 #endif diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h index 5bc56962a4..0b4662c1d7 100644 --- a/linux-user/mips/syscall.h +++ b/linux-user/mips/syscall.h @@ -228,3 +228,4 @@ struct target_pt_regs { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS +#define TARGET_MINSIGSTKSZ 2048 diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h index a7f5a5802a..39b8bedf05 100644 --- a/linux-user/mips64/syscall.h +++ b/linux-user/mips64/syscall.h @@ -225,3 +225,4 @@ struct target_pt_regs { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS +#define TARGET_MINSIGSTKSZ 2048 diff --git a/linux-user/openrisc/syscall.h b/linux-user/openrisc/syscall.h index c3b36da83c..e5e618099f 100644 --- a/linux-user/openrisc/syscall.h +++ b/linux-user/openrisc/syscall.h @@ -23,3 +23,5 @@ struct target_pt_regs { #define UNAME_MACHINE "openrisc" #define UNAME_MINIMUM_RELEASE "2.6.32" + +#define TARGET_MINSIGSTKSZ 2048 diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h index db92bbee17..5311cc6987 100644 --- a/linux-user/ppc/syscall.h +++ b/linux-user/ppc/syscall.h @@ -69,3 +69,5 @@ struct target_revectored_struct { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS + +#define TARGET_MINSIGSTKSZ 2048 diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h index aaad512d4d..b11a3b2690 100644 --- a/linux-user/s390x/syscall.h +++ b/linux-user/s390x/syscall.h @@ -24,3 +24,4 @@ struct target_pt_regs { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS2 +#define TARGET_MINSIGSTKSZ 2048 diff --git a/linux-user/sh4/syscall.h b/linux-user/sh4/syscall.h index ccd2216e38..285ecf3a79 100644 --- a/linux-user/sh4/syscall.h +++ b/linux-user/sh4/syscall.h @@ -11,3 +11,5 @@ struct target_pt_regs { #define UNAME_MACHINE "sh4" #define UNAME_MINIMUM_RELEASE "2.6.32" + +#define TARGET_MINSIGSTKSZ 2048 diff --git a/linux-user/signal.c b/linux-user/signal.c index 1141054be2..26929c59de 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -617,6 +617,15 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) { struct target_sigaltstack *uss; struct target_sigaltstack ss; + size_t minstacksize = TARGET_MINSIGSTKSZ; + +#if defined(TARGET_PPC64) + /* ELF V2 for PPC64 has a 4K minimum stack size for signal handlers */ + struct image_info *image = ((TaskState *)thread_cpu->opaque)->info; + if (get_ppc64_abi(image) > 1) { + minstacksize = 4096; + } +#endif ret = -TARGET_EFAULT; if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) { @@ -642,8 +651,9 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) ss.ss_sp = 0; } else { ret = -TARGET_ENOMEM; - if (ss.ss_size < MINSIGSTKSZ) + if (ss.ss_size < minstacksize) { goto out; + } } target_sigaltstack_used.ss_sp = ss.ss_sp; diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/syscall.h index 9549ea0a2f..ae4074414f 100644 --- a/linux-user/sparc/syscall.h +++ b/linux-user/sparc/syscall.h @@ -15,3 +15,4 @@ struct target_pt_regs { * and copy_thread(). */ #define TARGET_CLONE_BACKWARDS +#define TARGET_MINSIGSTKSZ 4096 diff --git a/linux-user/sparc64/syscall.h b/linux-user/sparc64/syscall.h index 82b1680cb6..816a00f568 100644 --- a/linux-user/sparc64/syscall.h +++ b/linux-user/sparc64/syscall.h @@ -16,3 +16,4 @@ struct target_pt_regs { * and copy_thread(). */ #define TARGET_CLONE_BACKWARDS +#define TARGET_MINSIGSTKSZ 4096 diff --git a/linux-user/unicore32/syscall.h b/linux-user/unicore32/syscall.h index f7e55254cf..3ed623721a 100644 --- a/linux-user/unicore32/syscall.h +++ b/linux-user/unicore32/syscall.h @@ -53,4 +53,6 @@ struct target_pt_regs { #define UNAME_MACHINE "UniCore-II" #define UNAME_MINIMUM_RELEASE "2.6.32" +#define TARGET_MINSIGSTKSZ 2048 + #endif /* __UC32_SYSCALL_H__ */ diff --git a/linux-user/x86_64/syscall.h b/linux-user/x86_64/syscall.h index e03b5a0cfc..5828b91026 100644 --- a/linux-user/x86_64/syscall.h +++ b/linux-user/x86_64/syscall.h @@ -97,3 +97,4 @@ struct target_msqid64_ds { #define TARGET_ARCH_SET_FS 0x1002 #define TARGET_ARCH_GET_FS 0x1003 #define TARGET_ARCH_GET_GS 0x1004 +#define TARGET_MINSIGSTKSZ 2048 From 8fbe8fdfbc7576c58c59b605354457cc02076304 Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Tue, 12 Aug 2014 13:53:41 -0500 Subject: [PATCH 19/22] linux-user: clock_nanosleep errno Handling on PPC The clock_nanosleep syscall is unusual in that it returns positive numbers in error handling situations, versus returning -1 and setting errno, or returning a negative errno value. On POWER, the kernel will set the SO bit of CR0 to indicate failure in a syscall. QEMU has generic handling to do this for syscalls with standard return values. Add special case code for clock_nanosleep to handle CR0 properly. Signed-off-by: Tom Musta Reviewed-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ed32f9723f..450f22dcc1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -9033,6 +9033,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL)); if (arg4) host_to_target_timespec(arg4, &ts); + +#if defined(TARGET_PPC) + /* clock_nanosleep is odd in that it returns positive errno values. + * On PPC, CR0 bit 3 should be set in such a situation. */ + if (ret) { + ((CPUPPCState *)cpu_env)->crf[0] |= 1; + } +#endif break; } #endif From 6f6a40328b6f4679082583c2b3a949cda451a991 Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Tue, 12 Aug 2014 13:53:42 -0500 Subject: [PATCH 20/22] linux-user: Support target-to-host translation of mlockall argument The argument to the mlockall system call is not necessarily the same on all platforms and thus may require translation prior to passing to the host. For example, PowerPC 64 bit platforms define values for MCL_CURRENT (0x2000) and MCL_FUTURE (0x4000) which are different from Intel platforms (0x1 and 0x2, respectively) Signed-off-by: Tom Musta Signed-off-by: Riku Voipio --- linux-user/aarch64/syscall.h | 2 ++ linux-user/alpha/syscall.h | 2 ++ linux-user/arm/syscall.h | 2 ++ linux-user/cris/syscall.h | 2 ++ linux-user/i386/syscall.h | 2 ++ linux-user/m68k/syscall.h | 2 ++ linux-user/microblaze/syscall.h | 2 ++ linux-user/mips/syscall.h | 2 ++ linux-user/mips64/syscall.h | 2 ++ linux-user/openrisc/syscall.h | 2 ++ linux-user/ppc/syscall.h | 2 ++ linux-user/s390x/syscall.h | 2 ++ linux-user/sh4/syscall.h | 2 ++ linux-user/sparc/syscall.h | 2 ++ linux-user/sparc64/syscall.h | 2 ++ linux-user/syscall.c | 17 ++++++++++++++++- linux-user/unicore32/syscall.h | 2 ++ linux-user/x86_64/syscall.h | 2 ++ 18 files changed, 50 insertions(+), 1 deletion(-) diff --git a/linux-user/aarch64/syscall.h b/linux-user/aarch64/syscall.h index d1f48232f3..dc72a15c5e 100644 --- a/linux-user/aarch64/syscall.h +++ b/linux-user/aarch64/syscall.h @@ -9,3 +9,5 @@ struct target_pt_regs { #define UNAME_MINIMUM_RELEASE "3.8.0" #define TARGET_CLONE_BACKWARDS #define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/alpha/syscall.h b/linux-user/alpha/syscall.h index 3adedeba30..245cff2545 100644 --- a/linux-user/alpha/syscall.h +++ b/linux-user/alpha/syscall.h @@ -253,3 +253,5 @@ struct target_pt_regs { #define TARGET_UAC_NOFIX 2 #define TARGET_UAC_SIGBUS 4 #define TARGET_MINSIGSTKSZ 4096 +#define TARGET_MLOCKALL_MCL_CURRENT 0x2000 +#define TARGET_MLOCKALL_MCL_FUTURE 0x4000 diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index cdadb0ce82..3844a96112 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/syscall.h @@ -46,3 +46,5 @@ struct target_pt_regs { #define TARGET_CLONE_BACKWARDS #define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/cris/syscall.h b/linux-user/cris/syscall.h index a75bcc49ea..2957b0d6ae 100644 --- a/linux-user/cris/syscall.h +++ b/linux-user/cris/syscall.h @@ -40,5 +40,7 @@ struct target_pt_regs { #define TARGET_CLONE_BACKWARDS2 #define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 #endif diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h index acf685622d..906aaac0b1 100644 --- a/linux-user/i386/syscall.h +++ b/linux-user/i386/syscall.h @@ -148,3 +148,5 @@ struct target_vm86plus_struct { #define TARGET_CLONE_BACKWARDS #define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/m68k/syscall.h b/linux-user/m68k/syscall.h index f8553f8c11..9218493a44 100644 --- a/linux-user/m68k/syscall.h +++ b/linux-user/m68k/syscall.h @@ -19,5 +19,7 @@ struct target_pt_regs { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 void do_m68k_simcall(CPUM68KState *, int); diff --git a/linux-user/microblaze/syscall.h b/linux-user/microblaze/syscall.h index 2a5e160b03..3c1ed27c04 100644 --- a/linux-user/microblaze/syscall.h +++ b/linux-user/microblaze/syscall.h @@ -50,5 +50,7 @@ struct target_pt_regs { #define TARGET_CLONE_BACKWARDS #define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 #endif diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h index 0b4662c1d7..35ca23b166 100644 --- a/linux-user/mips/syscall.h +++ b/linux-user/mips/syscall.h @@ -229,3 +229,5 @@ struct target_pt_regs { #define TARGET_CLONE_BACKWARDS #define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h index 39b8bedf05..6733107ddb 100644 --- a/linux-user/mips64/syscall.h +++ b/linux-user/mips64/syscall.h @@ -226,3 +226,5 @@ struct target_pt_regs { #define TARGET_CLONE_BACKWARDS #define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/openrisc/syscall.h b/linux-user/openrisc/syscall.h index e5e618099f..8ac03656d4 100644 --- a/linux-user/openrisc/syscall.h +++ b/linux-user/openrisc/syscall.h @@ -25,3 +25,5 @@ struct target_pt_regs { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h index 5311cc6987..0daf5cd2df 100644 --- a/linux-user/ppc/syscall.h +++ b/linux-user/ppc/syscall.h @@ -71,3 +71,5 @@ struct target_revectored_struct { #define TARGET_CLONE_BACKWARDS #define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 0x2000 +#define TARGET_MLOCKALL_MCL_FUTURE 0x4000 diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h index b11a3b2690..35f170af25 100644 --- a/linux-user/s390x/syscall.h +++ b/linux-user/s390x/syscall.h @@ -25,3 +25,5 @@ struct target_pt_regs { #define TARGET_CLONE_BACKWARDS2 #define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/sh4/syscall.h b/linux-user/sh4/syscall.h index 285ecf3a79..7aa4f239c5 100644 --- a/linux-user/sh4/syscall.h +++ b/linux-user/sh4/syscall.h @@ -13,3 +13,5 @@ struct target_pt_regs { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/syscall.h index ae4074414f..58573b92ea 100644 --- a/linux-user/sparc/syscall.h +++ b/linux-user/sparc/syscall.h @@ -16,3 +16,5 @@ struct target_pt_regs { */ #define TARGET_CLONE_BACKWARDS #define TARGET_MINSIGSTKSZ 4096 +#define TARGET_MLOCKALL_MCL_CURRENT 0x2000 +#define TARGET_MLOCKALL_MCL_FUTURE 0x4000 diff --git a/linux-user/sparc64/syscall.h b/linux-user/sparc64/syscall.h index 816a00f568..8398d3f463 100644 --- a/linux-user/sparc64/syscall.h +++ b/linux-user/sparc64/syscall.h @@ -17,3 +17,5 @@ struct target_pt_regs { */ #define TARGET_CLONE_BACKWARDS #define TARGET_MINSIGSTKSZ 4096 +#define TARGET_MLOCKALL_MCL_CURRENT 0x2000 +#define TARGET_MLOCKALL_MCL_FUTURE 0x4000 diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 450f22dcc1..1da216e2fb 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4968,6 +4968,21 @@ static inline abi_long target_to_host_sigevent(struct sigevent *host_sevp, return 0; } +#if defined(TARGET_NR_mlockall) +static inline int target_to_host_mlockall_arg(int arg) +{ + int result = 0; + + if (arg & TARGET_MLOCKALL_MCL_CURRENT) { + result |= MCL_CURRENT; + } + if (arg & TARGET_MLOCKALL_MCL_FUTURE) { + result |= MCL_FUTURE; + } + return result; +} +#endif + #if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat) static inline abi_long host_to_target_stat64(void *cpu_env, abi_ulong target_addr, @@ -6820,7 +6835,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_mlockall case TARGET_NR_mlockall: - ret = get_errno(mlockall(arg1)); + ret = get_errno(mlockall(target_to_host_mlockall_arg(arg1))); break; #endif #ifdef TARGET_NR_munlockall diff --git a/linux-user/unicore32/syscall.h b/linux-user/unicore32/syscall.h index 3ed623721a..385a97562d 100644 --- a/linux-user/unicore32/syscall.h +++ b/linux-user/unicore32/syscall.h @@ -54,5 +54,7 @@ struct target_pt_regs { #define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 #endif /* __UC32_SYSCALL_H__ */ diff --git a/linux-user/x86_64/syscall.h b/linux-user/x86_64/syscall.h index 5828b91026..88b3c3fe31 100644 --- a/linux-user/x86_64/syscall.h +++ b/linux-user/x86_64/syscall.h @@ -98,3 +98,5 @@ struct target_msqid64_ds { #define TARGET_ARCH_GET_FS 0x1003 #define TARGET_ARCH_GET_GS 0x1004 #define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MLOCKALL_MCL_CURRENT 1 +#define TARGET_MLOCKALL_MCL_FUTURE 2 From 29560a6cb7a7a705de3d7dfb44e8b1c0a12ad37d Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Tue, 12 Aug 2014 13:53:43 -0500 Subject: [PATCH 21/22] linux-user: writev Partial Writes Although not technically not required by POSIX, the writev system call will typically write out its buffers individually. That is, if the first buffer is written successfully, but the second buffer pointer is invalid, then the first chuck will be written and its size is returned. Signed-off-by: Tom Musta Reviewed-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1da216e2fb..ebdc70e4ca 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1803,6 +1803,7 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr, abi_ulong total_len, max_len; int i; int err = 0; + bool bad_address = false; if (count == 0) { errno = 0; @@ -1843,9 +1844,20 @@ static struct iovec *lock_iovec(int type, abi_ulong target_addr, vec[i].iov_base = 0; } else { vec[i].iov_base = lock_user(type, base, len, copy); + /* If the first buffer pointer is bad, this is a fault. But + * subsequent bad buffers will result in a partial write; this + * is realized by filling the vector with null pointers and + * zero lengths. */ if (!vec[i].iov_base) { - err = EFAULT; - goto fail; + if (i == 0) { + err = EFAULT; + goto fail; + } else { + bad_address = true; + } + } + if (bad_address) { + len = 0; } if (len > max_len - total_len) { len = max_len - total_len; From 29e03fcb62d413cf5fba06978346893ab72a1f64 Mon Sep 17 00:00:00 2001 From: zhanghailiang Date: Thu, 14 Aug 2014 15:29:18 +0800 Subject: [PATCH 22/22] linux-user: check return value of malloc() Signed-off-by: zhanghailiang Acked-by: Riku Voipio Signed-off-by: Riku Voipio --- linux-user/syscall.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ebdc70e4ca..7ff7c21255 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -2904,6 +2904,10 @@ static inline abi_long do_msgsnd(int msqid, abi_long msgp, if (!lock_user_struct(VERIFY_READ, target_mb, msgp, 0)) return -TARGET_EFAULT; host_mb = malloc(msgsz+sizeof(long)); + if (!host_mb) { + unlock_user_struct(target_mb, msgp, 0); + return -TARGET_ENOMEM; + } host_mb->mtype = (abi_long) tswapal(target_mb->mtype); memcpy(host_mb->mtext, target_mb->mtext, msgsz); ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));