diff options
Diffstat (limited to 'linux-user')
-rw-r--r-- | linux-user/elfload.c | 2 | ||||
-rw-r--r-- | linux-user/host/riscv32/hostdep.h | 11 | ||||
-rw-r--r-- | linux-user/host/riscv64/hostdep.h | 34 | ||||
-rw-r--r-- | linux-user/host/riscv64/safe-syscall.inc.S | 77 | ||||
-rw-r--r-- | linux-user/linuxload.c | 14 | ||||
-rw-r--r-- | linux-user/main.c | 4 | ||||
-rw-r--r-- | linux-user/mmap.c | 10 | ||||
-rw-r--r-- | linux-user/ppc/signal.c | 28 | ||||
-rw-r--r-- | linux-user/qemu.h | 10 | ||||
-rw-r--r-- | linux-user/signal.c | 16 | ||||
-rw-r--r-- | linux-user/strace.c | 4 | ||||
-rw-r--r-- | linux-user/syscall.c | 63 | ||||
-rw-r--r-- | linux-user/syscall_defs.h | 4 | ||||
-rw-r--r-- | linux-user/uaccess.c | 2 | ||||
-rw-r--r-- | linux-user/vm86.c | 2 | ||||
-rw-r--r-- | linux-user/x86_64/target_syscall.h | 2 |
16 files changed, 229 insertions, 54 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 5bccd2e243..4cff9e1a31 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -2844,7 +2844,7 @@ struct elf_note_info { struct target_elf_prstatus *prstatus; /* NT_PRSTATUS */ struct target_elf_prpsinfo *psinfo; /* NT_PRPSINFO */ - QTAILQ_HEAD(thread_list_head, elf_thread_status) thread_list; + QTAILQ_HEAD(, elf_thread_status) thread_list; #if 0 /* * Current version of ELF coredump doesn't support diff --git a/linux-user/host/riscv32/hostdep.h b/linux-user/host/riscv32/hostdep.h new file mode 100644 index 0000000000..adf9edbf2d --- /dev/null +++ b/linux-user/host/riscv32/hostdep.h @@ -0,0 +1,11 @@ +/* + * hostdep.h : things which are dependent on the host architecture + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef RISCV32_HOSTDEP_H +#define RISCV32_HOSTDEP_H + +#endif diff --git a/linux-user/host/riscv64/hostdep.h b/linux-user/host/riscv64/hostdep.h new file mode 100644 index 0000000000..865f0fb9ff --- /dev/null +++ b/linux-user/host/riscv64/hostdep.h @@ -0,0 +1,34 @@ +/* + * hostdep.h : things which are dependent on the host architecture + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef RISCV64_HOSTDEP_H +#define RISCV64_HOSTDEP_H + +/* We have a safe-syscall.inc.S */ +#define HAVE_SAFE_SYSCALL + +#ifndef __ASSEMBLER__ + +/* These are defined by the safe-syscall.inc.S file */ +extern char safe_syscall_start[]; +extern char safe_syscall_end[]; + +/* Adjust the signal context to rewind out of safe-syscall if we're in it */ +static inline void rewind_if_in_safe_syscall(void *puc) +{ + ucontext_t *uc = puc; + unsigned long *pcreg = &uc->uc_mcontext.__gregs[REG_PC]; + + if (*pcreg > (uintptr_t)safe_syscall_start + && *pcreg < (uintptr_t)safe_syscall_end) { + *pcreg = (uintptr_t)safe_syscall_start; + } +} + +#endif /* __ASSEMBLER__ */ + +#endif diff --git a/linux-user/host/riscv64/safe-syscall.inc.S b/linux-user/host/riscv64/safe-syscall.inc.S new file mode 100644 index 0000000000..9ca3fbfd1e --- /dev/null +++ b/linux-user/host/riscv64/safe-syscall.inc.S @@ -0,0 +1,77 @@ +/* + * safe-syscall.inc.S : host-specific assembly fragment + * to handle signals occurring at the same time as system calls. + * This is intended to be included by linux-user/safe-syscall.S + * + * Written by Richard Henderson <rth@twiddle.net> + * Copyright (C) 2018 Linaro, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + + .global safe_syscall_base + .global safe_syscall_start + .global safe_syscall_end + .type safe_syscall_base, @function + .type safe_syscall_start, @function + .type safe_syscall_end, @function + + /* + * This is the entry point for making a system call. The calling + * convention here is that of a C varargs function with the + * first argument an 'int *' to the signal_pending flag, the + * second one the system call number (as a 'long'), and all further + * arguments being syscall arguments (also 'long'). + * We return a long which is the syscall's return value, which + * may be negative-errno on failure. Conversion to the + * -1-and-errno-set convention is done by the calling wrapper. + */ +safe_syscall_base: + .cfi_startproc + /* + * The syscall calling convention is nearly the same as C: + * we enter with a0 == *signal_pending + * a1 == syscall number + * a2 ... a7 == syscall arguments + * and return the result in a0 + * and the syscall instruction needs + * a7 == syscall number + * a0 ... a5 == syscall arguments + * and returns the result in a0 + * Shuffle everything around appropriately. + */ + mv t0, a0 /* signal_pending pointer */ + mv t1, a1 /* syscall number */ + mv a0, a2 /* syscall arguments */ + mv a1, a3 + mv a2, a4 + mv a3, a5 + mv a4, a6 + mv a5, a7 + mv a7, t1 + + /* + * This next sequence of code works in conjunction with the + * rewind_if_safe_syscall_function(). If a signal is taken + * and the interrupted PC is anywhere between 'safe_syscall_start' + * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'. + * The code sequence must therefore be able to cope with this, and + * the syscall instruction must be the final one in the sequence. + */ +safe_syscall_start: + /* If signal_pending is non-zero, don't do the call */ + lw t1, 0(t0) + bnez t1, 0f + scall +safe_syscall_end: + /* code path for having successfully executed the syscall */ + ret + +0: + /* code path when we didn't execute the syscall */ + li a0, -TARGET_ERESTARTSYS + ret + .cfi_endproc + + .size safe_syscall_base, .-safe_syscall_base diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c index 6f0d6054ce..a27e1d0d8b 100644 --- a/linux-user/linuxload.c +++ b/linux-user/linuxload.c @@ -38,15 +38,15 @@ static int prepare_binprm(struct linux_binprm *bprm) int retval; if(fstat(bprm->fd, &st) < 0) { - return(-errno); + return(-errno); } mode = st.st_mode; if(!S_ISREG(mode)) { /* Must be regular file */ - return(-EACCES); + return(-EACCES); } if(!(mode & 0111)) { /* Must have at least one execute bit set */ - return(-EACCES); + return(-EACCES); } bprm->e_uid = geteuid(); @@ -54,7 +54,7 @@ static int prepare_binprm(struct linux_binprm *bprm) /* Set-uid? */ if(mode & S_ISUID) { - bprm->e_uid = st.st_uid; + bprm->e_uid = st.st_uid; } /* Set-gid? */ @@ -64,13 +64,13 @@ static int prepare_binprm(struct linux_binprm *bprm) * executable. */ if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { - bprm->e_gid = st.st_gid; + bprm->e_gid = st.st_gid; } retval = read(bprm->fd, bprm->buf, BPRM_BUF_SIZE); if (retval < 0) { - perror("prepare_binprm"); - exit(-1); + perror("prepare_binprm"); + exit(-1); } if (retval < BPRM_BUF_SIZE) { /* Make sure the rest of the loader won't read garbage. */ diff --git a/linux-user/main.c b/linux-user/main.c index 923cbb753a..a0aba9cb1e 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -740,8 +740,8 @@ int main(int argc, char **argv, char **envp) target_argc = argc - optind; target_argv = calloc(target_argc + 1, sizeof (char *)); if (target_argv == NULL) { - (void) fprintf(stderr, "Unable to allocate memory for target_argv\n"); - exit(EXIT_FAILURE); + (void) fprintf(stderr, "Unable to allocate memory for target_argv\n"); + exit(EXIT_FAILURE); } /* diff --git a/linux-user/mmap.c b/linux-user/mmap.c index 41e0983ce8..e0249efe4f 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -485,11 +485,11 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot, end = start + len; real_end = HOST_PAGE_ALIGN(end); - /* - * Test if requested memory area fits target address space - * It can fail only on 64-bit host with 32-bit target. - * On any other target/host host mmap() handles this error correctly. - */ + /* + * Test if requested memory area fits target address space + * It can fail only on 64-bit host with 32-bit target. + * On any other target/host host mmap() handles this error correctly. + */ if (!guest_range_valid(start, len)) { errno = ENOMEM; goto fail; diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c index 2ae120a2bc..619a56950d 100644 --- a/linux-user/ppc/signal.c +++ b/linux-user/ppc/signal.c @@ -258,8 +258,8 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame) /* Save Altivec registers if necessary. */ if (env->insns_flags & PPC_ALTIVEC) { uint32_t *vrsave; - for (i = 0; i < ARRAY_SIZE(env->avr); i++) { - ppc_avr_t *avr = &env->avr[i]; + for (i = 0; i < 32; i++) { + ppc_avr_t *avr = cpu_avr_ptr(env, i); ppc_avr_t *vreg = (ppc_avr_t *)&frame->mc_vregs.altivec[i]; __put_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]); @@ -281,15 +281,17 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame) /* Save VSX second halves */ if (env->insns_flags2 & PPC2_VSX) { uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34]; - for (i = 0; i < ARRAY_SIZE(env->vsr); i++) { - __put_user(env->vsr[i], &vsregs[i]); + for (i = 0; i < 32; i++) { + uint64_t *vsrl = cpu_vsrl_ptr(env, i); + __put_user(*vsrl, &vsregs[i]); } } /* Save floating point registers. */ if (env->insns_flags & PPC_FLOAT) { - for (i = 0; i < ARRAY_SIZE(env->fpr); i++) { - __put_user(env->fpr[i], &frame->mc_fregs[i]); + for (i = 0; i < 32; i++) { + uint64_t *fpr = cpu_fpr_ptr(env, i); + __put_user(*fpr, &frame->mc_fregs[i]); } __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]); } @@ -373,8 +375,8 @@ static void restore_user_regs(CPUPPCState *env, #else v_regs = (ppc_avr_t *)frame->mc_vregs.altivec; #endif - for (i = 0; i < ARRAY_SIZE(env->avr); i++) { - ppc_avr_t *avr = &env->avr[i]; + for (i = 0; i < 32; i++) { + ppc_avr_t *avr = cpu_avr_ptr(env, i); ppc_avr_t *vreg = &v_regs[i]; __get_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]); @@ -393,16 +395,18 @@ static void restore_user_regs(CPUPPCState *env, /* Restore VSX second halves */ if (env->insns_flags2 & PPC2_VSX) { uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34]; - for (i = 0; i < ARRAY_SIZE(env->vsr); i++) { - __get_user(env->vsr[i], &vsregs[i]); + for (i = 0; i < 32; i++) { + uint64_t *vsrl = cpu_vsrl_ptr(env, i); + __get_user(*vsrl, &vsregs[i]); } } /* Restore floating point registers. */ if (env->insns_flags & PPC_FLOAT) { uint64_t fpscr; - for (i = 0; i < ARRAY_SIZE(env->fpr); i++) { - __get_user(env->fpr[i], &frame->mc_fregs[i]); + for (i = 0; i < 32; i++) { + uint64_t *fpr = cpu_fpr_ptr(env, i); + __get_user(*fpr, &frame->mc_fregs[i]); } __get_user(fpscr, &frame->mc_fregs[32]); env->fpscr = (uint32_t) fpscr; diff --git a/linux-user/qemu.h b/linux-user/qemu.h index dd5771ce0c..ef400cb78a 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -50,7 +50,7 @@ struct image_info { abi_ulong env_strings; abi_ulong file_string; uint32_t elf_flags; - int personality; + int personality; abi_ulong alignment; /* The fields below are used in FDPIC mode. */ @@ -174,7 +174,7 @@ extern unsigned long mmap_min_addr; struct linux_binprm { char buf[BPRM_BUF_SIZE] __attribute__((aligned)); abi_ulong p; - int fd; + int fd; int e_uid, e_gid; int argc, envc; char **argv; @@ -474,17 +474,13 @@ static inline int access_ok(int type, abi_ulong addr, abi_ulong size) * functions than host-endian unaligned load/store plus tswapN. * - The pragmas are necessary only to silence a clang false-positive * warning: see https://bugs.llvm.org/show_bug.cgi?id=39113 . - * - We have to disable -Wpragmas warnings to avoid a complaint about - * an unknown warning type from older compilers that don't know about - * -Waddress-of-packed-member. * - gcc has bugs in its _Pragma() support in some versions, eg * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83256 -- so we only * include the warning-suppression pragmas for clang */ -#ifdef __clang__ +#if defined(__clang__) && __has_warning("-Waddress-of-packed-member") #define PRAGMA_DISABLE_PACKED_WARNING \ _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wpragmas\""); \ _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"") #define PRAGMA_REENABLE_PACKED_WARNING \ diff --git a/linux-user/signal.c b/linux-user/signal.c index 602b631b92..e2c0b37173 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -727,7 +727,7 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) } #endif - ret = -TARGET_EFAULT; + ret = -TARGET_EFAULT; if (!lock_user_struct(VERIFY_READ, uss, uss_addr, 1)) { goto out; } @@ -736,25 +736,25 @@ abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp) __get_user(ss.ss_flags, &uss->ss_flags); unlock_user_struct(uss, uss_addr, 0); - ret = -TARGET_EPERM; - if (on_sig_stack(sp)) + ret = -TARGET_EPERM; + if (on_sig_stack(sp)) goto out; - ret = -TARGET_EINVAL; - if (ss.ss_flags != TARGET_SS_DISABLE + ret = -TARGET_EINVAL; + if (ss.ss_flags != TARGET_SS_DISABLE && ss.ss_flags != TARGET_SS_ONSTACK && ss.ss_flags != 0) goto out; - if (ss.ss_flags == TARGET_SS_DISABLE) { + if (ss.ss_flags == TARGET_SS_DISABLE) { ss.ss_size = 0; ss.ss_sp = 0; - } else { + } else { ret = -TARGET_ENOMEM; if (ss.ss_size < minstacksize) { goto out; } - } + } target_sigaltstack_used.ss_sp = ss.ss_sp; target_sigaltstack_used.ss_size = ss.ss_size; diff --git a/linux-user/strace.c b/linux-user/strace.c index d1d14945f9..7318392e57 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -647,11 +647,11 @@ print_execve(const struct syscallname *name, for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) { abi_ulong *arg_ptr, arg_addr; - arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1); + arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1); if (!arg_ptr) return; arg_addr = tswapal(*arg_ptr); - unlock_user(arg_ptr, arg_ptr_addr, 0); + unlock_user(arg_ptr, arg_ptr_addr, 0); if (!arg_addr) break; if ((s = lock_user_string(arg_addr))) { diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 280137da8c..b5786d4fc1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -902,7 +902,7 @@ abi_long do_brk(abi_ulong new_brk) } target_brk = new_brk; DEBUGF_BRK(TARGET_ABI_FMT_lx " (new_brk <= brk_page)\n", target_brk); - return target_brk; + return target_brk; } /* We need to allocate more memory after the brk... Note that @@ -2352,6 +2352,45 @@ static abi_long do_getsockopt(int sockfd, int level, int optname, break; } break; + case SOL_IPV6: + switch (optname) { + case IPV6_MTU_DISCOVER: + case IPV6_MTU: + case IPV6_V6ONLY: + case IPV6_RECVPKTINFO: + case IPV6_UNICAST_HOPS: + case IPV6_MULTICAST_HOPS: + case IPV6_MULTICAST_LOOP: + case IPV6_RECVERR: + case IPV6_RECVHOPLIMIT: + case IPV6_2292HOPLIMIT: + case IPV6_CHECKSUM: + if (get_user_u32(len, optlen)) + return -TARGET_EFAULT; + if (len < 0) + return -TARGET_EINVAL; + lv = sizeof(lv); + ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv)); + if (ret < 0) + return ret; + if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) { + len = 1; + if (put_user_u32(len, optlen) + || put_user_u8(val, optval_addr)) + return -TARGET_EFAULT; + } else { + if (len > sizeof(int)) + len = sizeof(int); + if (put_user_u32(len, optlen) + || put_user_u32(val, optval_addr)) + return -TARGET_EFAULT; + } + break; + default: + ret = -TARGET_ENOPROTOOPT; + break; + } + break; default: unimplemented: gemu_log("getsockopt level=%d optname=%d not yet supported\n", @@ -9677,8 +9716,15 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, arg4 = arg5; arg5 = arg6; } - if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) - return -TARGET_EFAULT; + if (arg2 == 0 && arg3 == 0) { + /* Special-case NULL buffer and zero length, which should succeed */ + p = 0; + } else { + p = lock_user(VERIFY_WRITE, arg2, arg3, 0); + if (!p) { + return -TARGET_EFAULT; + } + } ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5))); unlock_user(p, arg2, ret); return ret; @@ -9687,8 +9733,15 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, arg4 = arg5; arg5 = arg6; } - if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) - return -TARGET_EFAULT; + if (arg2 == 0 && arg3 == 0) { + /* Special-case NULL buffer and zero length, which should succeed */ + p = 0; + } else { + p = lock_user(VERIFY_READ, arg2, arg3, 1); + if (!p) { + return -TARGET_EFAULT; + } + } ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5))); unlock_user(p, arg2, 0); return ret; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 99bbce083c..12c8407144 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -1807,7 +1807,7 @@ struct target_stat { abi_ulong st_rdev; abi_long st_size; abi_long st_blksize; - abi_long st_blocks; /* Number 512-byte blocks allocated. */ + abi_long st_blocks; /* Number 512-byte blocks allocated. */ abi_ulong target_st_atime; abi_ulong target_st_atime_nsec; @@ -1816,7 +1816,7 @@ struct target_stat { abi_ulong target_st_ctime; abi_ulong target_st_ctime_nsec; - abi_long __unused[3]; + abi_long __unused[3]; }; #elif defined(TARGET_S390X) struct target_stat { diff --git a/linux-user/uaccess.c b/linux-user/uaccess.c index 0a5c0b0b29..e215ecc2a6 100644 --- a/linux-user/uaccess.c +++ b/linux-user/uaccess.c @@ -30,7 +30,7 @@ abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len) if ((ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0))) { memcpy(ghptr, hptr, len); - unlock_user(ghptr, gaddr, len); + unlock_user(ghptr, gaddr, len); } else ret = -TARGET_EFAULT; diff --git a/linux-user/vm86.c b/linux-user/vm86.c index 3829b9a677..9c393df424 100644 --- a/linux-user/vm86.c +++ b/linux-user/vm86.c @@ -257,7 +257,7 @@ void handle_vm86_trap(CPUX86State *env, int trapno) #define CHECK_IF_IN_TRAP() \ if ((ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) && \ (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_TFpendig)) \ - newflags |= TF_MASK + newflags |= TF_MASK #define VM86_FAULT_RETURN \ if ((ts->vm86plus.vm86plus.flags & TARGET_force_return_for_pic) && \ diff --git a/linux-user/x86_64/target_syscall.h b/linux-user/x86_64/target_syscall.h index 983fb23d9b..5e221e1d9d 100644 --- a/linux-user/x86_64/target_syscall.h +++ b/linux-user/x86_64/target_syscall.h @@ -12,7 +12,7 @@ struct target_pt_regs { abi_ulong rbp; abi_ulong rbx; /* arguments: non interrupts/non tracing syscalls only save up to here */ - abi_ulong r11; + abi_ulong r11; abi_ulong r10; abi_ulong r9; abi_ulong r8; |