From d9fe91d8689b078acfd27bc7c4a4e1efd5bbcf65 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 28 Jul 2016 12:57:59 +0100 Subject: [PATCH 1/5] linux-user: Use correct alignment for long long on i386 guests For i386, the ABI specifies that 'long long' (8 byte values) need only be 4 aligned, but we were requiring them to be 8-aligned. This meant we were laying out the target_epoll_event structure wrongly. Add a suitable ifdef to abitypes.h to specify the i386-specific alignment requirement. Reported-by: Icenowy Zheng Signed-off-by: Peter Maydell Reviewed-by: Laurent Vivier Signed-off-by: Riku Voipio --- include/exec/user/abitypes.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/exec/user/abitypes.h b/include/exec/user/abitypes.h index a09d6c64ff..ba188608c2 100644 --- a/include/exec/user/abitypes.h +++ b/include/exec/user/abitypes.h @@ -15,6 +15,10 @@ #define ABI_LLONG_ALIGNMENT 2 #endif +#if defined(TARGET_I386) && !defined(TARGET_X86_64) +#define ABI_LLONG_ALIGNMENT 4 +#endif + #ifndef ABI_SHORT_ALIGNMENT #define ABI_SHORT_ALIGNMENT 2 #endif From ba4b3f668abf1fcde204c8f3185ea6edeec6eaa3 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 Jul 2016 13:02:19 +0100 Subject: [PATCH 2/5] linux-user: Fix memchr() argument in open_self_cmdline() In open_self_cmdline() we look for a 0 in the buffer we read from /prc/self/cmdline. We were incorrectly passing the length of our buf[] array to memchr() as the length to search, rather than the number of bytes we actually read into it, which could be shorter. This was spotted by Coverity (because it could result in our trying to pass a negative length argument to write()). Signed-off-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 ca6a2b495a..092ff4ee21 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6856,7 +6856,7 @@ static int open_self_cmdline(void *cpu_env, int fd) if (!word_skipped) { /* Skip the first string, which is the path to qemu-*-static instead of the actual command. */ - cp_buf = memchr(buf, 0, sizeof(buf)); + cp_buf = memchr(buf, 0, nb_read); if (cp_buf) { /* Null byte found, skip one string */ cp_buf++; From 332c9781f6a7c496adf605a1be72776598c7adc2 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 12 Jul 2016 13:02:16 +0100 Subject: [PATCH 3/5] linux-user: Don't write off end of new_utsname buffer Use g_strlcpy() rather than strcpy() to copy the uname string into the structure we return to the guest for the uname syscall. This avoids overrunning the buffer if the user passed us an overlong string via the QEMU command line. We fix a comment typo while we're in the neighbourhood. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 092ff4ee21..5bc42c017e 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -9237,12 +9237,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto efault; ret = get_errno(sys_uname(buf)); if (!is_error(ret)) { - /* Overrite the native machine name with whatever is being + /* Overwrite the native machine name with whatever is being emulated. */ strcpy (buf->machine, cpu_to_uname_machine(cpu_env)); /* Allow the user to override the reported release. */ - if (qemu_uname_release && *qemu_uname_release) - strcpy (buf->release, qemu_uname_release); + if (qemu_uname_release && *qemu_uname_release) { + g_strlcpy(buf->release, qemu_uname_release, + sizeof(buf->release)); + } } unlock_user_struct(buf, arg1, 1); } From 005eb2ae1ff6728de7e6998b7456bd72d4456383 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 15 Jul 2016 16:50:47 +0100 Subject: [PATCH 4/5] linux-user: Fix target_semid_ds structure definition The target_semid_ds structure is not correct for all architectures: the padding fields should only exist for: * 32-bit ABIs * x86 It is also misnamed, since it is following the kernel semid64_ds structure (QEMU doesn't support the legacy semid_ds structure at all). Rename the struct, provide a correct generic definition and allow the oddball x86 architecture to provide its own version. This fixes broken SYSV semaphores for all our 64-bit architectures except x86 and ppc. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/syscall.c | 17 ++++++++++------- linux-user/x86_64/target_structs.h | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5bc42c017e..df6f2a9d0f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3754,27 +3754,30 @@ static struct shm_region { bool in_use; } shm_regions[N_SHM_REGIONS]; -struct target_semid_ds +#ifndef TARGET_SEMID64_DS +/* asm-generic version of this struct */ +struct target_semid64_ds { struct target_ipc_perm sem_perm; abi_ulong sem_otime; -#if !defined(TARGET_PPC64) +#if TARGET_ABI_BITS == 32 abi_ulong __unused1; #endif abi_ulong sem_ctime; -#if !defined(TARGET_PPC64) +#if TARGET_ABI_BITS == 32 abi_ulong __unused2; #endif abi_ulong sem_nsems; abi_ulong __unused3; abi_ulong __unused4; }; +#endif static inline abi_long target_to_host_ipc_perm(struct ipc_perm *host_ip, abi_ulong target_addr) { struct target_ipc_perm *target_ip; - struct target_semid_ds *target_sd; + struct target_semid64_ds *target_sd; if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) return -TARGET_EFAULT; @@ -3802,7 +3805,7 @@ static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr, struct ipc_perm *host_ip) { struct target_ipc_perm *target_ip; - struct target_semid_ds *target_sd; + struct target_semid64_ds *target_sd; if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) return -TARGET_EFAULT; @@ -3829,7 +3832,7 @@ static inline abi_long host_to_target_ipc_perm(abi_ulong target_addr, static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd, abi_ulong target_addr) { - struct target_semid_ds *target_sd; + struct target_semid64_ds *target_sd; if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1)) return -TARGET_EFAULT; @@ -3845,7 +3848,7 @@ static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd, static inline abi_long host_to_target_semid_ds(abi_ulong target_addr, struct semid_ds *host_sd) { - struct target_semid_ds *target_sd; + struct target_semid64_ds *target_sd; if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0)) return -TARGET_EFAULT; diff --git a/linux-user/x86_64/target_structs.h b/linux-user/x86_64/target_structs.h index 348982703e..b6e82a822c 100644 --- a/linux-user/x86_64/target_structs.h +++ b/linux-user/x86_64/target_structs.h @@ -55,4 +55,19 @@ struct target_shmid_ds { abi_ulong __unused5; }; +/* The x86 definition differs from the generic one in that the + * two padding fields exist whether the ABI is 32 bits or 64 bits. + */ +#define TARGET_SEMID64_DS +struct target_semid64_ds { + struct target_ipc_perm sem_perm; + abi_ulong sem_otime; + abi_ulong __unused1; + abi_ulong sem_ctime; + abi_ulong __unused2; + abi_ulong sem_nsems; + abi_ulong __unused3; + abi_ulong __unused4; +}; + #endif From ef4330c23bb47b97a859dbdbae1c784fd2ca402f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 22 Jul 2016 13:41:52 +0100 Subject: [PATCH 5/5] linux-user: Handle brk() attempts with very large sizes In do_brk(), we were inadvertently truncating the size of a requested brk() from the guest by putting it into an 'int' variable. This meant that we would incorrectly report success back to the guest rather than a failed allocation, typically resulting in the guest then segfaulting. Use abi_ulong instead. This fixes a crash in the '31370.cc' test in the gcc libstdc++ test suite (the test case starts by trying to allocate a very large size and reduces the size until the allocation succeeds). Signed-off-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 df6f2a9d0f..833f853200 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -839,7 +839,7 @@ void target_set_brk(abi_ulong new_brk) abi_long do_brk(abi_ulong new_brk) { abi_long mapped_addr; - int new_alloc_size; + abi_ulong new_alloc_size; DEBUGF_BRK("do_brk(" TARGET_ABI_FMT_lx ") -> ", new_brk);