linux-user pull request v2 for may 2016

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIVAwUAV0g0rrRIkN7ePJvAAQh+hA//TZOrmRskN7/PzlGp90pkNVL4Xm6LDNsj
 fvgzB4ceuA+eRv426ttSpYgZestZjxmb/29c5UJWvH0Otnhrxj0aNKimxAO4FCIV
 u2u73Mn4cTGZPfoMJesCYihC19LIFIpYFPjXTKz2UJ4Dg/ZLBd6KORDTC7kfXoSx
 9wTgaHZkbrUBCwWQ+0SKrbibPJWY4RHUkYCK4dxCCPFRVpGhYFt1vihjZpzDzzNH
 njjxr/GB8W1OByBI90TWUpx6e0YRqhKluuvr1ObezrK2/nCZhLwOkvgIB1yuew3e
 AwFz5wUFtx80FV3ThAKDoJadz6tVKPG67OG2w5DmgUrK6gpOTP9n1LcypTK+wti4
 /LNb9AhyEqsDD/apFQWNEEdYwCG6qjlaE01zp6ZQPgNUWpN1BSEDmikoHwpUqLaq
 fXfgJZyOItp6LP3Tajkto2h9iAdXI6eoJHQtMK562J89WZz1Bb4IJxONAkWZq5oV
 aQCOj0wD/vObUhMU72jLy2cd3kHM/RT5NliMhb+nbR9JY/WXbTeOn41hOhEnkJJJ
 bjRPCN2O3ULfi3yn3St2ByCngPUG954uqmR2OaOGwEHGx6E/UEkWsduUlRwwY1zK
 96pZvsHO8DSIDc5gNmUlvQlBc62v8b+KUcwsbloBCl2YGt9mbZNM9zi0Gg4R97MJ
 jHkpVjF4L4I=
 =/Nln
 -----END PGP SIGNATURE-----

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

linux-user pull request v2 for may 2016

# gpg: Signature made Fri 27 May 2016 12:51:10 BST using RSA key ID DE3C9BC0
# gpg: Good signature from "Riku Voipio <riku.voipio@iki.fi>"
# gpg:                 aka "Riku Voipio <riku.voipio@linaro.org>"

* remotes/riku/tags/pull-linux-user-20160527: (38 commits)
  linux-user,target-ppc: fix use of MSR_LE
  linux-user/signal.c: Use s390 target space address instead of host space
  linux-user/signal.c: Use target address instead of host address for microblaze restorer
  linux-user/signal.c: Generate opcode data for restorer in setup_rt_frame
  linux-user: arm: Remove ARM_cpsr and similar #defines
  linux-user: Use direct syscalls for setuid(), etc
  linux-user: x86_64: Don't use 16-bit UIDs
  linux-user: Use g_try_malloc() in do_msgrcv()
  linux-user: Handle msgrcv error case correctly
  linux-user: Handle negative values in timespec conversion
  linux-user: Use safe_syscall for futex syscall
  linux-user: Use safe_syscall for pselect, select syscalls
  linux-user: Use safe_syscall for execve syscall
  linux-user: Use safe_syscall for wait system calls
  linux-user: Use safe_syscall for open and openat system calls
  linux-user: Use safe_syscall for read and write system calls
  linux-user: Provide safe_syscall for fixing races between signals and syscalls
  linux-user: Add debug code to exercise restarting system calls
  linux-user: Support for restarting system calls for Microblaze targets
  linux-user: Set r14 on exit from microblaze syscall
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2016-05-27 14:05:48 +01:00
commit d6550e9ed2
31 changed files with 1522 additions and 955 deletions

View File

@ -108,7 +108,12 @@ obj-$(CONFIG_LIBDECNUMBER) += libdecnumber/dpd/decimal128.o
ifdef CONFIG_LINUX_USER ifdef CONFIG_LINUX_USER
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) -I$(SRC_PATH)/linux-user # Note that we only add linux-user/host/$ARCH if it exists, and
# that it must come before linux-user/host/generic in the search path.
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) \
$(patsubst %,-I%,$(wildcard $(SRC_PATH)/linux-user/host/$(ARCH))) \
-I$(SRC_PATH)/linux-user/host/generic \
-I$(SRC_PATH)/linux-user
obj-y += linux-user/ obj-y += linux-user/
obj-y += gdbstub.o thunk.o user-exec.o obj-y += gdbstub.o thunk.o user-exec.o

View File

@ -1,5 +1,6 @@
obj-y = main.o syscall.o strace.o mmap.o signal.o \ obj-y = main.o syscall.o strace.o mmap.o signal.o \
elfload.o linuxload.o uaccess.o uname.o elfload.o linuxload.o uaccess.o uname.o \
safe-syscall.o
obj-$(TARGET_HAS_BFLT) += flatload.o obj-$(TARGET_HAS_BFLT) += flatload.o
obj-$(TARGET_I386) += vm86.o obj-$(TARGET_I386) += vm86.o

View File

@ -27,6 +27,7 @@ static inline abi_ulong get_sp_from_cpustate(CPUAlphaState *state)
return state->ir[IR_SP]; return state->ir[IR_SP];
} }
/* From <asm/gentrap.h>. */ /* From <asm/gentrap.h>. */
#define TARGET_GEN_INTOVF -1 /* integer overflow */ #define TARGET_GEN_INTOVF -1 /* integer overflow */
#define TARGET_GEN_INTDIV -2 /* integer division by zero */ #define TARGET_GEN_INTDIV -2 /* integer division by zero */

View File

@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUARMState *state)
return state->regs[13]; return state->regs[13];
} }
#endif /* TARGET_SIGNAL_H */ #endif /* TARGET_SIGNAL_H */

View File

@ -4,29 +4,11 @@
/* this struct defines the way the registers are stored on the /* this struct defines the way the registers are stored on the
stack during a system call. */ stack during a system call. */
/* uregs[0..15] are r0 to r15; uregs[16] is CPSR; uregs[17] is ORIG_r0 */
struct target_pt_regs { struct target_pt_regs {
abi_long uregs[18]; abi_long uregs[18];
}; };
#define ARM_cpsr uregs[16]
#define ARM_pc uregs[15]
#define ARM_lr uregs[14]
#define ARM_sp uregs[13]
#define ARM_ip uregs[12]
#define ARM_fp uregs[11]
#define ARM_r10 uregs[10]
#define ARM_r9 uregs[9]
#define ARM_r8 uregs[8]
#define ARM_r7 uregs[7]
#define ARM_r6 uregs[6]
#define ARM_r5 uregs[5]
#define ARM_r4 uregs[4]
#define ARM_r3 uregs[3]
#define ARM_r2 uregs[2]
#define ARM_r1 uregs[1]
#define ARM_r0 uregs[0]
#define ARM_ORIG_r0 uregs[17]
#define ARM_SYSCALL_BASE 0x900000 #define ARM_SYSCALL_BASE 0x900000
#define ARM_THUMB_SYSCALL 0 #define ARM_THUMB_SYSCALL 0

View File

@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUCRISState *state)
return state->regs[14]; return state->regs[14];
} }
#endif /* TARGET_SIGNAL_H */ #endif /* TARGET_SIGNAL_H */

View File

@ -274,19 +274,20 @@ static inline void init_thread(struct target_pt_regs *regs,
abi_long stack = infop->start_stack; abi_long stack = infop->start_stack;
memset(regs, 0, sizeof(*regs)); memset(regs, 0, sizeof(*regs));
regs->ARM_cpsr = 0x10; regs->uregs[16] = ARM_CPU_MODE_USR;
if (infop->entry & 1) if (infop->entry & 1) {
regs->ARM_cpsr |= CPSR_T; regs->uregs[16] |= CPSR_T;
regs->ARM_pc = infop->entry & 0xfffffffe; }
regs->ARM_sp = infop->start_stack; regs->uregs[15] = infop->entry & 0xfffffffe;
regs->uregs[13] = infop->start_stack;
/* FIXME - what to for failure of get_user()? */ /* FIXME - what to for failure of get_user()? */
get_user_ual(regs->ARM_r2, stack + 8); /* envp */ get_user_ual(regs->uregs[2], stack + 8); /* envp */
get_user_ual(regs->ARM_r1, stack + 4); /* envp */ get_user_ual(regs->uregs[1], stack + 4); /* envp */
/* XXX: it seems that r0 is zeroed after ! */ /* XXX: it seems that r0 is zeroed after ! */
regs->ARM_r0 = 0; regs->uregs[0] = 0;
/* For uClinux PIC binaries. */ /* For uClinux PIC binaries. */
/* XXX: Linux does this only on ARM with no MMU (do we care ?) */ /* XXX: Linux does this only on ARM with no MMU (do we care ?) */
regs->ARM_r10 = infop->start_data; regs->uregs[10] = infop->start_data;
} }
#define ELF_NREG 18 #define ELF_NREG 18

View File

@ -139,3 +139,20 @@
/* for robust mutexes */ /* for robust mutexes */
#define TARGET_EOWNERDEAD 130 /* Owner died */ #define TARGET_EOWNERDEAD 130 /* Owner died */
#define TARGET_ENOTRECOVERABLE 131 /* State not recoverable */ #define TARGET_ENOTRECOVERABLE 131 /* State not recoverable */
/* QEMU internal, not visible to the guest. This is returned when a
* system call should be restarted, to tell the main loop that it
* should wind the guest PC backwards so it will re-execute the syscall
* after handling any pending signals. They match with the ones the guest
* kernel uses for the same purpose.
*/
#define TARGET_ERESTARTSYS 512 /* Restart system call (if SA_RESTART) */
/* QEMU internal, not visible to the guest. This is returned by the
* do_sigreturn() code after a successful sigreturn syscall, to indicate
* that it has correctly set the guest registers and so the main loop
* should not touch them. We use the value the guest would use for
* ERESTART_NOINTR (which is kernel internal) to guarantee that we won't
* clash with a valid guest errno now or in the future.
*/
#define TARGET_QEMU_ESIGRETURN 513 /* Return from signal */

View File

@ -0,0 +1,20 @@
/*
* hostdep.h : fallback generic version of header for things
* which are dependent on the host architecture
*
* * Written by Peter Maydell <peter.maydell@linaro.org>
*
* Copyright (C) 2016 Linaro Limited
*
* 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 QEMU_HOSTDEP_H
#define QEMU_HOSTDEP_H
/* This is the fallback header which is only used if the host
* architecture doesn't provide one in linux-user/host/$ARCH.
*/
#endif

View File

@ -0,0 +1,38 @@
/*
* hostdep.h : things which are dependent on the host architecture
*
* * Written by Peter Maydell <peter.maydell@linaro.org>
*
* Copyright (C) 2016 Linaro Limited
*
* 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 QEMU_HOSTDEP_H
#define QEMU_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)
{
struct ucontext *uc = puc;
greg_t *pcreg = &uc->uc_mcontext.gregs[REG_RIP];
if (*pcreg > (uintptr_t)safe_syscall_start
&& *pcreg < (uintptr_t)safe_syscall_end) {
*pcreg = (uintptr_t)safe_syscall_start;
}
}
#endif /* __ASSEMBLER__ */
#endif

View File

@ -0,0 +1,81 @@
/*
* 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
*
* Copyright (C) 2015 Timothy Edward Baldwin <T.E.Baldwin99@members.leeds.ac.uk>
*
* 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
/* 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:
/* This saves a frame pointer and aligns the stack for the syscall.
* (It's unclear if the syscall ABI has the same stack alignment
* requirements as the userspace function call ABI, but better safe than
* sorry. Appendix A2 of http://www.x86-64.org/documentation/abi.pdf
* does not list any ABI differences regarding stack alignment.)
*/
push %rbp
/* The syscall calling convention isn't the same as the
* C one:
* we enter with rdi == *signal_pending
* rsi == syscall number
* rdx, rcx, r8, r9, (stack), (stack) == syscall arguments
* and return the result in rax
* and the syscall instruction needs
* rax == syscall number
* rdi, rsi, rdx, r10, r8, r9 == syscall arguments
* and returns the result in rax
* Shuffle everything around appropriately.
* Note that syscall will trash rcx and r11.
*/
mov %rsi, %rax /* syscall number */
mov %rdi, %rbp /* signal_pending pointer */
/* and the syscall arguments */
mov %rdx, %rdi
mov %rcx, %rsi
mov %r8, %rdx
mov %r9, %r10
mov 16(%rsp), %r8
mov 24(%rsp), %r9
/* 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 */
testl $1, (%rbp)
jnz return_ERESTARTSYS
syscall
safe_syscall_end:
/* code path for having successfully executed the syscall */
pop %rbp
ret
return_ERESTARTSYS:
/* code path when we didn't execute the syscall */
mov $-TARGET_ERESTARTSYS, %rax
pop %rbp
ret
.size safe_syscall_base, .-safe_syscall_base

View File

@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUM68KState *state)
return state->aregs[7]; return state->aregs[7];
} }
#endif /* TARGET_SIGNAL_H */ #endif /* TARGET_SIGNAL_H */

View File

@ -285,6 +285,7 @@ void cpu_loop(CPUX86State *env)
CPUState *cs = CPU(x86_env_get_cpu(env)); CPUState *cs = CPU(x86_env_get_cpu(env));
int trapnr; int trapnr;
abi_ulong pc; abi_ulong pc;
abi_ulong ret;
target_siginfo_t info; target_siginfo_t info;
for(;;) { for(;;) {
@ -294,28 +295,38 @@ void cpu_loop(CPUX86State *env)
switch(trapnr) { switch(trapnr) {
case 0x80: case 0x80:
/* linux syscall from int $0x80 */ /* linux syscall from int $0x80 */
env->regs[R_EAX] = do_syscall(env, ret = do_syscall(env,
env->regs[R_EAX], env->regs[R_EAX],
env->regs[R_EBX], env->regs[R_EBX],
env->regs[R_ECX], env->regs[R_ECX],
env->regs[R_EDX], env->regs[R_EDX],
env->regs[R_ESI], env->regs[R_ESI],
env->regs[R_EDI], env->regs[R_EDI],
env->regs[R_EBP], env->regs[R_EBP],
0, 0); 0, 0);
if (ret == -TARGET_ERESTARTSYS) {
env->eip -= 2;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
env->regs[R_EAX] = ret;
}
break; break;
#ifndef TARGET_ABI32 #ifndef TARGET_ABI32
case EXCP_SYSCALL: case EXCP_SYSCALL:
/* linux syscall from syscall instruction */ /* linux syscall from syscall instruction */
env->regs[R_EAX] = do_syscall(env, ret = do_syscall(env,
env->regs[R_EAX], env->regs[R_EAX],
env->regs[R_EDI], env->regs[R_EDI],
env->regs[R_ESI], env->regs[R_ESI],
env->regs[R_EDX], env->regs[R_EDX],
env->regs[10], env->regs[10],
env->regs[8], env->regs[8],
env->regs[9], env->regs[9],
0, 0); 0, 0);
if (ret == -TARGET_ERESTARTSYS) {
env->eip -= 2;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
env->regs[R_EAX] = ret;
}
break; break;
#endif #endif
case EXCP0B_NOSEG: case EXCP0B_NOSEG:
@ -716,6 +727,7 @@ void cpu_loop(CPUARMState *env)
unsigned int n, insn; unsigned int n, insn;
target_siginfo_t info; target_siginfo_t info;
uint32_t addr; uint32_t addr;
abi_ulong ret;
for(;;) { for(;;) {
cpu_exec_start(cs); cpu_exec_start(cs);
@ -854,15 +866,20 @@ void cpu_loop(CPUARMState *env)
break; break;
} }
} else { } else {
env->regs[0] = do_syscall(env, ret = do_syscall(env,
n, n,
env->regs[0], env->regs[0],
env->regs[1], env->regs[1],
env->regs[2], env->regs[2],
env->regs[3], env->regs[3],
env->regs[4], env->regs[4],
env->regs[5], env->regs[5],
0, 0); 0, 0);
if (ret == -TARGET_ERESTARTSYS) {
env->regs[15] -= env->thumb ? 2 : 4;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
env->regs[0] = ret;
}
} }
} else { } else {
goto error; goto error;
@ -1045,6 +1062,7 @@ void cpu_loop(CPUARMState *env)
{ {
CPUState *cs = CPU(arm_env_get_cpu(env)); CPUState *cs = CPU(arm_env_get_cpu(env));
int trapnr, sig; int trapnr, sig;
abi_long ret;
target_siginfo_t info; target_siginfo_t info;
for (;;) { for (;;) {
@ -1054,15 +1072,20 @@ void cpu_loop(CPUARMState *env)
switch (trapnr) { switch (trapnr) {
case EXCP_SWI: case EXCP_SWI:
env->xregs[0] = do_syscall(env, ret = do_syscall(env,
env->xregs[8], env->xregs[8],
env->xregs[0], env->xregs[0],
env->xregs[1], env->xregs[1],
env->xregs[2], env->xregs[2],
env->xregs[3], env->xregs[3],
env->xregs[4], env->xregs[4],
env->xregs[5], env->xregs[5],
0, 0); 0, 0);
if (ret == -TARGET_ERESTARTSYS) {
env->pc -= 4;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
env->xregs[0] = ret;
}
break; break;
case EXCP_INTERRUPT: case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */ /* just indicate that signals should be handled asap */
@ -1148,7 +1171,7 @@ void cpu_loop(CPUUniCore32State *env)
cpu_set_tls(env, env->regs[0]); cpu_set_tls(env, env->regs[0]);
env->regs[0] = 0; env->regs[0] = 0;
} else { } else {
env->regs[0] = do_syscall(env, abi_long ret = do_syscall(env,
n, n,
env->regs[0], env->regs[0],
env->regs[1], env->regs[1],
@ -1157,6 +1180,11 @@ void cpu_loop(CPUUniCore32State *env)
env->regs[4], env->regs[4],
env->regs[5], env->regs[5],
0, 0); 0, 0);
if (ret == -TARGET_ERESTARTSYS) {
env->regs[31] -= 4;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
env->regs[0] = ret;
}
} }
} else { } else {
goto error; goto error;
@ -1353,6 +1381,9 @@ void cpu_loop (CPUSPARCState *env)
env->regwptr[2], env->regwptr[3], env->regwptr[2], env->regwptr[3],
env->regwptr[4], env->regwptr[5], env->regwptr[4], env->regwptr[5],
0, 0); 0, 0);
if (ret == -TARGET_ERESTARTSYS || ret == -TARGET_QEMU_ESIGRETURN) {
break;
}
if ((abi_ulong)ret >= (abi_ulong)(-515)) { if ((abi_ulong)ret >= (abi_ulong)(-515)) {
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
env->xcc |= PSR_CARRY; env->xcc |= PSR_CARRY;
@ -1964,6 +1995,10 @@ void cpu_loop(CPUPPCState *env)
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4], ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->gpr[7], env->gpr[5], env->gpr[6], env->gpr[7],
env->gpr[8], 0, 0); env->gpr[8], 0, 0);
if (ret == -TARGET_ERESTARTSYS) {
env->nip -= 4;
break;
}
if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) { if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
/* Returning from a successful sigreturn syscall. /* Returning from a successful sigreturn syscall.
Avoid corrupting register state. */ Avoid corrupting register state. */
@ -2505,6 +2540,10 @@ done_syscall:
env->active_tc.gpr[8], env->active_tc.gpr[9], env->active_tc.gpr[8], env->active_tc.gpr[9],
env->active_tc.gpr[10], env->active_tc.gpr[11]); env->active_tc.gpr[10], env->active_tc.gpr[11]);
# endif /* O32 */ # endif /* O32 */
if (ret == -TARGET_ERESTARTSYS) {
env->active_tc.PC -= 4;
break;
}
if (ret == -TARGET_QEMU_ESIGRETURN) { if (ret == -TARGET_QEMU_ESIGRETURN) {
/* Returning from a successful sigreturn syscall. /* Returning from a successful sigreturn syscall.
Avoid clobbering register state. */ Avoid clobbering register state. */
@ -2685,6 +2724,7 @@ void cpu_loop(CPUOpenRISCState *env)
{ {
CPUState *cs = CPU(openrisc_env_get_cpu(env)); CPUState *cs = CPU(openrisc_env_get_cpu(env));
int trapnr, gdbsig; int trapnr, gdbsig;
abi_long ret;
for (;;) { for (;;) {
cpu_exec_start(cs); cpu_exec_start(cs);
@ -2730,14 +2770,19 @@ void cpu_loop(CPUOpenRISCState *env)
break; break;
case EXCP_SYSCALL: case EXCP_SYSCALL:
env->pc += 4; /* 0xc00; */ env->pc += 4; /* 0xc00; */
env->gpr[11] = do_syscall(env, ret = do_syscall(env,
env->gpr[11], /* return value */ env->gpr[11], /* return value */
env->gpr[3], /* r3 - r7 are params */ env->gpr[3], /* r3 - r7 are params */
env->gpr[4], env->gpr[4],
env->gpr[5], env->gpr[5],
env->gpr[6], env->gpr[6],
env->gpr[7], env->gpr[7],
env->gpr[8], 0, 0); env->gpr[8], 0, 0);
if (ret == -TARGET_ERESTARTSYS) {
env->pc -= 4;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
env->gpr[11] = ret;
}
break; break;
case EXCP_FPE: case EXCP_FPE:
qemu_log_mask(CPU_LOG_INT, "\nFloating point error\n"); qemu_log_mask(CPU_LOG_INT, "\nFloating point error\n");
@ -2792,7 +2837,11 @@ void cpu_loop(CPUSH4State *env)
env->gregs[0], env->gregs[0],
env->gregs[1], env->gregs[1],
0, 0); 0, 0);
env->gregs[0] = ret; if (ret == -TARGET_ERESTARTSYS) {
env->pc -= 2;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
env->gregs[0] = ret;
}
break; break;
case EXCP_INTERRUPT: case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */ /* just indicate that signals should be handled asap */
@ -2865,7 +2914,11 @@ void cpu_loop(CPUCRISState *env)
env->pregs[7], env->pregs[7],
env->pregs[11], env->pregs[11],
0, 0); 0, 0);
env->regs[10] = ret; if (ret == -TARGET_ERESTARTSYS) {
env->pc -= 2;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
env->regs[10] = ret;
}
break; break;
case EXCP_DEBUG: case EXCP_DEBUG:
{ {
@ -2929,7 +2982,19 @@ void cpu_loop(CPUMBState *env)
env->regs[9], env->regs[9],
env->regs[10], env->regs[10],
0, 0); 0, 0);
env->regs[3] = ret; if (ret == -TARGET_ERESTARTSYS) {
/* Wind back to before the syscall. */
env->sregs[SR_PC] -= 4;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
env->regs[3] = ret;
}
/* All syscall exits result in guest r14 being equal to the
* PC we return to, because the kernel syscall exit "rtbd" does
* this. (This is true even for sigreturn(); note that r14 is
* not a userspace-usable register, as the kernel may clobber it
* at any point.)
*/
env->regs[14] = env->sregs[SR_PC];
break; break;
case EXCP_HW_EXCP: case EXCP_HW_EXCP:
env->regs[17] = env->sregs[SR_PC] + 4; env->regs[17] = env->sregs[SR_PC] + 4;
@ -3037,18 +3102,24 @@ void cpu_loop(CPUM68KState *env)
break; break;
case EXCP_TRAP0: case EXCP_TRAP0:
{ {
abi_long ret;
ts->sim_syscalls = 0; ts->sim_syscalls = 0;
n = env->dregs[0]; n = env->dregs[0];
env->pc += 2; env->pc += 2;
env->dregs[0] = do_syscall(env, ret = do_syscall(env,
n, n,
env->dregs[1], env->dregs[1],
env->dregs[2], env->dregs[2],
env->dregs[3], env->dregs[3],
env->dregs[4], env->dregs[4],
env->dregs[5], env->dregs[5],
env->aregs[0], env->aregs[0],
0, 0); 0, 0);
if (ret == -TARGET_ERESTARTSYS) {
env->pc -= 2;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
env->dregs[0] = ret;
}
} }
break; break;
case EXCP_INTERRUPT: case EXCP_INTERRUPT:
@ -3229,8 +3300,11 @@ void cpu_loop(CPUAlphaState *env)
env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A2], env->ir[IR_A3],
env->ir[IR_A4], env->ir[IR_A5], env->ir[IR_A4], env->ir[IR_A5],
0, 0); 0, 0);
if (trapnr == TARGET_NR_sigreturn if (sysret == -TARGET_ERESTARTSYS) {
|| trapnr == TARGET_NR_rt_sigreturn) { env->pc -= 4;
break;
}
if (sysret == -TARGET_QEMU_ESIGRETURN) {
break; break;
} }
/* Syscall writes 0 to V0 to bypass error check, similar /* Syscall writes 0 to V0 to bypass error check, similar
@ -3327,6 +3401,7 @@ void cpu_loop(CPUS390XState *env)
int trapnr, n, sig; int trapnr, n, sig;
target_siginfo_t info; target_siginfo_t info;
target_ulong addr; target_ulong addr;
abi_long ret;
while (1) { while (1) {
cpu_exec_start(cs); cpu_exec_start(cs);
@ -3344,9 +3419,14 @@ void cpu_loop(CPUS390XState *env)
n = env->regs[1]; n = env->regs[1];
} }
env->psw.addr += env->int_svc_ilen; env->psw.addr += env->int_svc_ilen;
env->regs[2] = do_syscall(env, n, env->regs[2], env->regs[3], ret = do_syscall(env, n, env->regs[2], env->regs[3],
env->regs[4], env->regs[5], env->regs[4], env->regs[5],
env->regs[6], env->regs[7], 0, 0); env->regs[6], env->regs[7], 0, 0);
if (ret == -TARGET_ERESTARTSYS) {
env->psw.addr -= env->int_svc_ilen;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
env->regs[2] = ret;
}
break; break;
case EXCP_DEBUG: case EXCP_DEBUG:
@ -3638,15 +3718,20 @@ void cpu_loop(CPUTLGState *env)
cpu_exec_end(cs); cpu_exec_end(cs);
switch (trapnr) { switch (trapnr) {
case TILEGX_EXCP_SYSCALL: case TILEGX_EXCP_SYSCALL:
env->regs[TILEGX_R_RE] = do_syscall(env, env->regs[TILEGX_R_NR], {
env->regs[0], env->regs[1], abi_ulong ret = do_syscall(env, env->regs[TILEGX_R_NR],
env->regs[2], env->regs[3], env->regs[0], env->regs[1],
env->regs[4], env->regs[5], env->regs[2], env->regs[3],
env->regs[6], env->regs[7]); env->regs[4], env->regs[5],
env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(env->regs[TILEGX_R_RE]) env->regs[6], env->regs[7]);
? - env->regs[TILEGX_R_RE] if (ret == -TARGET_ERESTARTSYS) {
: 0; env->pc -= 8;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
env->regs[TILEGX_R_RE] = ret;
env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(ret) ? -ret : 0;
}
break; break;
}
case TILEGX_EXCP_OPCODE_EXCH: case TILEGX_EXCP_OPCODE_EXCH:
do_exch(env, true, false); do_exch(env, true, false);
break; break;

View File

@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUMBState *state)
return state->regs[14]; return state->regs[14];
} }
#endif /* TARGET_SIGNAL_H */ #endif /* TARGET_SIGNAL_H */

View File

@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
return state->active_tc.gpr[29]; return state->active_tc.gpr[29];
} }
#endif /* TARGET_SIGNAL_H */ #endif /* TARGET_SIGNAL_H */

View File

@ -222,10 +222,6 @@ struct target_pt_regs {
#define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ #define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */
/* Nasty hack: define a fake errno value for use by sigreturn. */
#define TARGET_QEMU_ESIGRETURN 255
#define UNAME_MACHINE "mips" #define UNAME_MACHINE "mips"
#define UNAME_MINIMUM_RELEASE "2.6.32" #define UNAME_MINIMUM_RELEASE "2.6.32"

View File

@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
return state->active_tc.gpr[29]; return state->active_tc.gpr[29];
} }
#endif /* TARGET_SIGNAL_H */ #endif /* TARGET_SIGNAL_H */

View File

@ -219,10 +219,6 @@ struct target_pt_regs {
#define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */ #define TARGET_ENOTRECOVERABLE 166 /* State not recoverable */
/* Nasty hack: define a fake errno value for use by sigreturn. */
#define TARGET_QEMU_ESIGRETURN 255
#define UNAME_MACHINE "mips64" #define UNAME_MACHINE "mips64"
#define UNAME_MINIMUM_RELEASE "2.6.32" #define UNAME_MINIMUM_RELEASE "2.6.32"

View File

@ -23,4 +23,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUOpenRISCState *state)
return state->gpr[1]; return state->gpr[1];
} }
#endif /* TARGET_SIGNAL_H */ #endif /* TARGET_SIGNAL_H */

View File

@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUPPCState *state)
return state->gpr[1]; return state->gpr[1];
} }
#endif /* TARGET_SIGNAL_H */ #endif /* TARGET_SIGNAL_H */

View File

@ -53,8 +53,6 @@ struct target_revectored_struct {
abi_ulong __map[8]; /* 256 bits */ abi_ulong __map[8]; /* 256 bits */
}; };
/* Nasty hack: define a fake errno value for use by sigreturn. */
#define TARGET_QEMU_ESIGRETURN 255
/* /*
* flags masks * flags masks

View File

@ -1,7 +1,7 @@
#ifndef QEMU_H #ifndef QEMU_H
#define QEMU_H #define QEMU_H
#include "hostdep.h"
#include "cpu.h" #include "cpu.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "exec/cpu_ldst.h" #include "exec/cpu_ldst.h"
@ -205,6 +205,131 @@ unsigned long init_guest_space(unsigned long host_start,
#include "qemu/log.h" #include "qemu/log.h"
/* safe_syscall.S */
/**
* safe_syscall:
* @int number: number of system call to make
* ...: arguments to the system call
*
* Call a system call if guest signal not pending.
* This has the same API as the libc syscall() function, except that it
* may return -1 with errno == TARGET_ERESTARTSYS if a signal was pending.
*
* Returns: the system call result, or -1 with an error code in errno
* (Errnos are host errnos; we rely on TARGET_ERESTARTSYS not clashing
* with any of the host errno values.)
*/
/* A guide to using safe_syscall() to handle interactions between guest
* syscalls and guest signals:
*
* Guest syscalls come in two flavours:
*
* (1) Non-interruptible syscalls
*
* These are guest syscalls that never get interrupted by signals and
* so never return EINTR. They can be implemented straightforwardly in
* QEMU: just make sure that if the implementation code has to make any
* blocking calls that those calls are retried if they return EINTR.
* It's also OK to implement these with safe_syscall, though it will be
* a little less efficient if a signal is delivered at the 'wrong' moment.
*
* (2) Interruptible syscalls
*
* These are guest syscalls that can be interrupted by signals and
* for which we need to either return EINTR or arrange for the guest
* syscall to be restarted. This category includes both syscalls which
* always restart (and in the kernel return -ERESTARTNOINTR), ones
* which only restart if there is no handler (kernel returns -ERESTARTNOHAND
* or -ERESTART_RESTARTBLOCK), and the most common kind which restart
* if the handler was registered with SA_RESTART (kernel returns
* -ERESTARTSYS). System calls which are only interruptible in some
* situations (like 'open') also need to be handled this way.
*
* Here it is important that the host syscall is made
* via this safe_syscall() function, and *not* via the host libc.
* If the host libc is used then the implementation will appear to work
* most of the time, but there will be a race condition where a
* signal could arrive just before we make the host syscall inside libc,
* and then then guest syscall will not correctly be interrupted.
* Instead the implementation of the guest syscall can use the safe_syscall
* function but otherwise just return the result or errno in the usual
* way; the main loop code will take care of restarting the syscall
* if appropriate.
*
* (If the implementation needs to make multiple host syscalls this is
* OK; any which might really block must be via safe_syscall(); for those
* which are only technically blocking (ie which we know in practice won't
* stay in the host kernel indefinitely) it's OK to use libc if necessary.
* You must be able to cope with backing out correctly if some safe_syscall
* you make in the implementation returns either -TARGET_ERESTARTSYS or
* EINTR though.)
*
*
* How and why the safe_syscall implementation works:
*
* The basic setup is that we make the host syscall via a known
* section of host native assembly. If a signal occurs, our signal
* handler checks the interrupted host PC against the addresse of that
* known section. If the PC is before or at the address of the syscall
* instruction then we change the PC to point at a "return
* -TARGET_ERESTARTSYS" code path instead, and then exit the signal handler
* (causing the safe_syscall() call to immediately return that value).
* Then in the main.c loop if we see this magic return value we adjust
* the guest PC to wind it back to before the system call, and invoke
* the guest signal handler as usual.
*
* This winding-back will happen in two cases:
* (1) signal came in just before we took the host syscall (a race);
* in this case we'll take the guest signal and have another go
* at the syscall afterwards, and this is indistinguishable for the
* guest from the timing having been different such that the guest
* signal really did win the race
* (2) signal came in while the host syscall was blocking, and the
* host kernel decided the syscall should be restarted;
* in this case we want to restart the guest syscall also, and so
* rewinding is the right thing. (Note that "restart" semantics mean
* "first call the signal handler, then reattempt the syscall".)
* The other situation to consider is when a signal came in while the
* host syscall was blocking, and the host kernel decided that the syscall
* should not be restarted; in this case QEMU's host signal handler will
* be invoked with the PC pointing just after the syscall instruction,
* with registers indicating an EINTR return; the special code in the
* handler will not kick in, and we will return EINTR to the guest as
* we should.
*
* Notice that we can leave the host kernel to make the decision for
* us about whether to do a restart of the syscall or not; we do not
* need to check SA_RESTART flags in QEMU or distinguish the various
* kinds of restartability.
*/
#ifdef HAVE_SAFE_SYSCALL
/* The core part of this function is implemented in assembly */
extern long safe_syscall_base(int *pending, long number, ...);
#define safe_syscall(...) \
({ \
long ret_; \
int *psp_ = &((TaskState *)thread_cpu->opaque)->signal_pending; \
ret_ = safe_syscall_base(psp_, __VA_ARGS__); \
if (is_error(ret_)) { \
errno = -ret_; \
ret_ = -1; \
} \
ret_; \
})
#else
/* Fallback for architectures which don't yet provide a safe-syscall assembly
* fragment; note that this is racy!
* This should go away when all host architectures have been updated.
*/
#define safe_syscall syscall
#endif
/* syscall.c */ /* syscall.c */
int host_to_target_waitstatus(int status); int host_to_target_waitstatus(int status);

View File

@ -23,4 +23,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUS390XState *state)
return state->regs[15]; return state->regs[15];
} }
#endif /* TARGET_SIGNAL_H */ #endif /* TARGET_SIGNAL_H */

30
linux-user/safe-syscall.S Normal file
View File

@ -0,0 +1,30 @@
/*
* safe-syscall.S : include the host-specific assembly fragment
* to handle signals occurring at the same time as system calls.
*
* Written by Peter Maydell <peter.maydell@linaro.org>
*
* Copyright (C) 2016 Linaro Limited
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "hostdep.h"
#include "errno_defs.h"
/* We have the correct host directory on our include path
* so that this will pull in the right fragment for the architecture.
*/
#ifdef HAVE_SAFE_SYSCALL
#include "safe-syscall.inc.S"
#endif
/* We must specifically say that we're happy for the stack to not be
* executable, otherwise the toolchain will default to assuming our
* assembly needs an executable stack and the whole QEMU binary will
* needlessly end up with one. This should be the last thing in this file.
*/
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack, "", %progbits
#endif

View File

@ -26,4 +26,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUSH4State *state)
return state->gregs[15]; return state->gregs[15];
} }
#endif /* TARGET_SIGNAL_H */ #endif /* TARGET_SIGNAL_H */

File diff suppressed because it is too large Load Diff

View File

@ -33,4 +33,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
return state->regwptr[UREG_FP]; return state->regwptr[UREG_FP];
} }
#endif /* TARGET_SIGNAL_H */ #endif /* TARGET_SIGNAL_H */

View File

@ -33,4 +33,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
return state->regwptr[UREG_FP]; return state->regwptr[UREG_FP];
} }
#endif /* TARGET_SIGNAL_H */ #endif /* TARGET_SIGNAL_H */

View File

@ -110,6 +110,10 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID) CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
//#define DEBUG //#define DEBUG
/* Define DEBUG_ERESTARTSYS to force every syscall to be restarted
* once. This exercises the codepaths for restart.
*/
//#define DEBUG_ERESTARTSYS
//#include <linux/msdos_fs.h> //#include <linux/msdos_fs.h>
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2]) #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
@ -355,18 +359,6 @@ static int sys_getcwd1(char *buf, size_t size)
return strlen(buf)+1; return strlen(buf)+1;
} }
static int sys_openat(int dirfd, const char *pathname, int flags, mode_t mode)
{
/*
* open(2) has extra parameter 'mode' when called with
* flag O_CREAT.
*/
if ((flags & O_CREAT) != 0) {
return (openat(dirfd, pathname, flags, mode));
}
return (openat(dirfd, pathname, flags));
}
#ifdef TARGET_NR_utimensat #ifdef TARGET_NR_utimensat
#ifdef CONFIG_UTIMENSAT #ifdef CONFIG_UTIMENSAT
static int sys_utimensat(int dirfd, const char *pathname, static int sys_utimensat(int dirfd, const char *pathname,
@ -438,15 +430,6 @@ _syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
size_t, sigsetsize) size_t, sigsetsize)
#endif #endif
#if defined(TARGET_NR_pselect6)
#ifndef __NR_pselect6
# define __NR_pselect6 -1
#endif
#define __NR_sys_pselect6 __NR_pselect6
_syscall6(int, sys_pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds,
fd_set *, exceptfds, struct timespec *, timeout, void *, sig);
#endif
#if defined(TARGET_NR_prlimit64) #if defined(TARGET_NR_prlimit64)
#ifndef __NR_prlimit64 #ifndef __NR_prlimit64
# define __NR_prlimit64 -1 # define __NR_prlimit64 -1
@ -619,15 +602,19 @@ static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
static inline int host_to_target_errno(int err) static inline int host_to_target_errno(int err)
{ {
if(host_to_target_errno_table[err]) if (err >= 0 && err < ERRNO_TABLE_SIZE &&
host_to_target_errno_table[err]) {
return host_to_target_errno_table[err]; return host_to_target_errno_table[err];
}
return err; return err;
} }
static inline int target_to_host_errno(int err) static inline int target_to_host_errno(int err)
{ {
if (target_to_host_errno_table[err]) if (err >= 0 && err < ERRNO_TABLE_SIZE &&
target_to_host_errno_table[err]) {
return target_to_host_errno_table[err]; return target_to_host_errno_table[err];
}
return err; return err;
} }
@ -652,6 +639,67 @@ char *target_strerror(int err)
return strerror(target_to_host_errno(err)); return strerror(target_to_host_errno(err));
} }
#define safe_syscall0(type, name) \
static type safe_##name(void) \
{ \
return safe_syscall(__NR_##name); \
}
#define safe_syscall1(type, name, type1, arg1) \
static type safe_##name(type1 arg1) \
{ \
return safe_syscall(__NR_##name, arg1); \
}
#define safe_syscall2(type, name, type1, arg1, type2, arg2) \
static type safe_##name(type1 arg1, type2 arg2) \
{ \
return safe_syscall(__NR_##name, arg1, arg2); \
}
#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \
static type safe_##name(type1 arg1, type2 arg2, type3 arg3) \
{ \
return safe_syscall(__NR_##name, arg1, arg2, arg3); \
}
#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \
type4, arg4) \
static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
{ \
return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4); \
}
#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \
type4, arg4, type5, arg5) \
static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
type5 arg5) \
{ \
return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
}
#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \
type4, arg4, type5, arg5, type6, arg6) \
static type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
type5 arg5, type6 arg6) \
{ \
return safe_syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
}
safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count)
safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count)
safe_syscall4(int, openat, int, dirfd, const char *, pathname, \
int, flags, mode_t, mode)
safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \
struct rusage *, rusage)
safe_syscall5(int, waitid, idtype_t, idtype, id_t, id, siginfo_t *, infop, \
int, options, struct rusage *, rusage)
safe_syscall3(int, execve, const char *, filename, char **, argv, char **, envp)
safe_syscall6(int, pselect6, int, nfds, fd_set *, readfds, fd_set *, writefds, \
fd_set *, exceptfds, struct timespec *, timeout, void *, sig)
safe_syscall6(int,futex,int *,uaddr,int,op,int,val, \
const struct timespec *,timeout,int *,uaddr2,int,val3)
static inline int host_to_target_sock_type(int host_type) static inline int host_to_target_sock_type(int host_type)
{ {
int target_type; int target_type;
@ -1062,7 +1110,8 @@ static abi_long do_select(int n,
{ {
fd_set rfds, wfds, efds; fd_set rfds, wfds, efds;
fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
struct timeval tv, *tv_ptr; struct timeval tv;
struct timespec ts, *ts_ptr;
abi_long ret; abi_long ret;
ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n); ret = copy_from_user_fdset_ptr(&rfds, &rfds_ptr, rfd_addr, n);
@ -1081,12 +1130,15 @@ static abi_long do_select(int n,
if (target_tv_addr) { if (target_tv_addr) {
if (copy_from_user_timeval(&tv, target_tv_addr)) if (copy_from_user_timeval(&tv, target_tv_addr))
return -TARGET_EFAULT; return -TARGET_EFAULT;
tv_ptr = &tv; ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000;
ts_ptr = &ts;
} else { } else {
tv_ptr = NULL; ts_ptr = NULL;
} }
ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr)); ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
ts_ptr, NULL));
if (!is_error(ret)) { if (!is_error(ret)) {
if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n)) if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
@ -1096,8 +1148,13 @@ static abi_long do_select(int n,
if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n)) if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
return -TARGET_EFAULT; return -TARGET_EFAULT;
if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv)) if (target_tv_addr) {
return -TARGET_EFAULT; tv.tv_sec = ts.tv_sec;
tv.tv_usec = ts.tv_nsec / 1000;
if (copy_to_user_timeval(target_tv_addr, &tv)) {
return -TARGET_EFAULT;
}
}
} }
return ret; return ret;
@ -3095,7 +3152,7 @@ static inline abi_long do_msgsnd(int msqid, abi_long msgp,
} }
static inline abi_long do_msgrcv(int msqid, abi_long msgp, static inline abi_long do_msgrcv(int msqid, abi_long msgp,
unsigned int msgsz, abi_long msgtyp, ssize_t msgsz, abi_long msgtyp,
int msgflg) int msgflg)
{ {
struct target_msgbuf *target_mb; struct target_msgbuf *target_mb;
@ -3103,10 +3160,18 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp,
struct msgbuf *host_mb; struct msgbuf *host_mb;
abi_long ret = 0; abi_long ret = 0;
if (msgsz < 0) {
return -TARGET_EINVAL;
}
if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0)) if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
return -TARGET_EFAULT; return -TARGET_EFAULT;
host_mb = g_malloc(msgsz+sizeof(long)); host_mb = g_try_malloc(msgsz + sizeof(long));
if (!host_mb) {
ret = -TARGET_ENOMEM;
goto end;
}
ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg)); ret = get_errno(msgrcv(msqid, host_mb, msgsz, msgtyp, msgflg));
if (ret > 0) { if (ret > 0) {
@ -5034,6 +5099,40 @@ static inline int tswapid(int id)
#endif /* USE_UID16 */ #endif /* USE_UID16 */
/* We must do direct syscalls for setting UID/GID, because we want to
* implement the Linux system call semantics of "change only for this thread",
* not the libc/POSIX semantics of "change for all threads in process".
* (See http://ewontfix.com/17/ for more details.)
* We use the 32-bit version of the syscalls if present; if it is not
* then either the host architecture supports 32-bit UIDs natively with
* the standard syscall, or the 16-bit UID is the best we can do.
*/
#ifdef __NR_setuid32
#define __NR_sys_setuid __NR_setuid32
#else
#define __NR_sys_setuid __NR_setuid
#endif
#ifdef __NR_setgid32
#define __NR_sys_setgid __NR_setgid32
#else
#define __NR_sys_setgid __NR_setgid
#endif
#ifdef __NR_setresuid32
#define __NR_sys_setresuid __NR_setresuid32
#else
#define __NR_sys_setresuid __NR_setresuid
#endif
#ifdef __NR_setresgid32
#define __NR_sys_setresgid __NR_setresgid32
#else
#define __NR_sys_setresgid __NR_setresgid
#endif
_syscall1(int, sys_setuid, uid_t, uid)
_syscall1(int, sys_setgid, gid_t, gid)
_syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
_syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
void syscall_init(void) void syscall_init(void)
{ {
IOCTLEntry *ie; IOCTLEntry *ie;
@ -5137,8 +5236,8 @@ static inline abi_long target_to_host_timespec(struct timespec *host_ts,
if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1)) if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
return -TARGET_EFAULT; return -TARGET_EFAULT;
host_ts->tv_sec = tswapal(target_ts->tv_sec); __get_user(host_ts->tv_sec, &target_ts->tv_sec);
host_ts->tv_nsec = tswapal(target_ts->tv_nsec); __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
unlock_user_struct(target_ts, target_addr, 0); unlock_user_struct(target_ts, target_addr, 0);
return 0; return 0;
} }
@ -5150,8 +5249,8 @@ static inline abi_long host_to_target_timespec(abi_ulong target_addr,
if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0)) if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
return -TARGET_EFAULT; return -TARGET_EFAULT;
target_ts->tv_sec = tswapal(host_ts->tv_sec); __put_user(host_ts->tv_sec, &target_ts->tv_sec);
target_ts->tv_nsec = tswapal(host_ts->tv_nsec); __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
unlock_user_struct(target_ts, target_addr, 1); unlock_user_struct(target_ts, target_addr, 1);
return 0; return 0;
} }
@ -5326,12 +5425,12 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
} else { } else {
pts = NULL; pts = NULL;
} }
return get_errno(sys_futex(g2h(uaddr), op, tswap32(val), return get_errno(safe_futex(g2h(uaddr), op, tswap32(val),
pts, NULL, val3)); pts, NULL, val3));
case FUTEX_WAKE: case FUTEX_WAKE:
return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0)); return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
case FUTEX_FD: case FUTEX_FD:
return get_errno(sys_futex(g2h(uaddr), op, val, NULL, NULL, 0)); return get_errno(safe_futex(g2h(uaddr), op, val, NULL, NULL, 0));
case FUTEX_REQUEUE: case FUTEX_REQUEUE:
case FUTEX_CMP_REQUEUE: case FUTEX_CMP_REQUEUE:
case FUTEX_WAKE_OP: case FUTEX_WAKE_OP:
@ -5341,11 +5440,11 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
to satisfy the compiler. We do not need to tswap TIMEOUT to satisfy the compiler. We do not need to tswap TIMEOUT
since it's not compared to guest memory. */ since it's not compared to guest memory. */
pts = (struct timespec *)(uintptr_t) timeout; pts = (struct timespec *)(uintptr_t) timeout;
return get_errno(sys_futex(g2h(uaddr), op, val, pts, return get_errno(safe_futex(g2h(uaddr), op, val, pts,
g2h(uaddr2), g2h(uaddr2),
(base_op == FUTEX_CMP_REQUEUE (base_op == FUTEX_CMP_REQUEUE
? tswap32(val3) ? tswap32(val3)
: val3))); : val3)));
default: default:
return -TARGET_ENOSYS; return -TARGET_ENOSYS;
} }
@ -5555,7 +5654,9 @@ static int open_self_cmdline(void *cpu_env, int fd)
nb_read = read(fd_orig, buf, sizeof(buf)); nb_read = read(fd_orig, buf, sizeof(buf));
if (nb_read < 0) { if (nb_read < 0) {
int e = errno;
fd_orig = close(fd_orig); fd_orig = close(fd_orig);
errno = e;
return -1; return -1;
} else if (nb_read == 0) { } else if (nb_read == 0) {
break; break;
@ -5575,7 +5676,9 @@ static int open_self_cmdline(void *cpu_env, int fd)
if (word_skipped) { if (word_skipped) {
if (write(fd, cp_buf, nb_read) != nb_read) { if (write(fd, cp_buf, nb_read) != nb_read) {
int e = errno;
close(fd_orig); close(fd_orig);
errno = e;
return -1; return -1;
} }
} }
@ -5595,7 +5698,7 @@ static int open_self_maps(void *cpu_env, int fd)
fp = fopen("/proc/self/maps", "r"); fp = fopen("/proc/self/maps", "r");
if (fp == NULL) { if (fp == NULL) {
return -EACCES; return -1;
} }
while ((read = getline(&line, &len, fp)) != -1) { while ((read = getline(&line, &len, fp)) != -1) {
@ -5739,7 +5842,7 @@ static int open_net_route(void *cpu_env, int fd)
fp = fopen("/proc/net/route", "r"); fp = fopen("/proc/net/route", "r");
if (fp == NULL) { if (fp == NULL) {
return -EACCES; return -1;
} }
/* read header */ /* read header */
@ -5789,7 +5892,7 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags,
if (is_proc_myself(pathname, "exe")) { if (is_proc_myself(pathname, "exe")) {
int execfd = qemu_getauxval(AT_EXECFD); int execfd = qemu_getauxval(AT_EXECFD);
return execfd ? execfd : get_errno(sys_openat(dirfd, exec_path, flags, mode)); return execfd ? execfd : safe_openat(dirfd, exec_path, flags, mode);
} }
for (fake_open = fakes; fake_open->filename; fake_open++) { for (fake_open = fakes; fake_open->filename; fake_open++) {
@ -5815,7 +5918,9 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags,
unlink(filename); unlink(filename);
if ((r = fake_open->fill(cpu_env, fd))) { if ((r = fake_open->fill(cpu_env, fd))) {
int e = errno;
close(fd); close(fd);
errno = e;
return r; return r;
} }
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
@ -5823,7 +5928,7 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags,
return fd; return fd;
} }
return get_errno(sys_openat(dirfd, path(pathname), flags, mode)); return safe_openat(dirfd, path(pathname), flags, mode);
} }
#define TIMER_MAGIC 0x0caf0000 #define TIMER_MAGIC 0x0caf0000
@ -5861,6 +5966,21 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
struct statfs stfs; struct statfs stfs;
void *p; void *p;
#if defined(DEBUG_ERESTARTSYS)
/* Debug-only code for exercising the syscall-restart code paths
* in the per-architecture cpu main loops: restart every syscall
* the guest makes once before letting it through.
*/
{
static int flag;
flag = !flag;
if (flag) {
return -TARGET_ERESTARTSYS;
}
}
#endif
#ifdef DEBUG #ifdef DEBUG
gemu_log("syscall %d", num); gemu_log("syscall %d", num);
#endif #endif
@ -5907,7 +6027,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
else { else {
if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
goto efault; goto efault;
ret = get_errno(read(arg1, p, arg3)); ret = get_errno(safe_read(arg1, p, arg3));
if (ret >= 0 && if (ret >= 0 &&
fd_trans_host_to_target_data(arg1)) { fd_trans_host_to_target_data(arg1)) {
ret = fd_trans_host_to_target_data(arg1)(p, ret); ret = fd_trans_host_to_target_data(arg1)(p, ret);
@ -5918,7 +6038,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_write: case TARGET_NR_write:
if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
goto efault; goto efault;
ret = get_errno(write(arg1, p, arg3)); ret = get_errno(safe_write(arg1, p, arg3));
unlock_user(p, arg2, 0); unlock_user(p, arg2, 0);
break; break;
#ifdef TARGET_NR_open #ifdef TARGET_NR_open
@ -5968,7 +6088,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_waitpid: case TARGET_NR_waitpid:
{ {
int status; int status;
ret = get_errno(waitpid(arg1, &status, arg3)); ret = get_errno(safe_wait4(arg1, &status, arg3, 0));
if (!is_error(ret) && arg2 && ret if (!is_error(ret) && arg2 && ret
&& put_user_s32(host_to_target_waitstatus(status), arg2)) && put_user_s32(host_to_target_waitstatus(status), arg2))
goto efault; goto efault;
@ -5980,7 +6100,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{ {
siginfo_t info; siginfo_t info;
info.si_pid = 0; info.si_pid = 0;
ret = get_errno(waitid(arg1, arg2, &info, arg4)); ret = get_errno(safe_waitid(arg1, arg2, &info, arg4, NULL));
if (!is_error(ret) && arg3 && info.si_pid != 0) { if (!is_error(ret) && arg3 && info.si_pid != 0) {
if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0))) if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
goto efault; goto efault;
@ -6106,7 +6226,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (!(p = lock_user_string(arg1))) if (!(p = lock_user_string(arg1)))
goto execve_efault; goto execve_efault;
ret = get_errno(execve(p, argp, envp)); /* Although execve() is not an interruptible syscall it is
* a special case where we must use the safe_syscall wrapper:
* if we allow a signal to happen before we make the host
* syscall then we will 'lose' it, because at the point of
* execve the process leaves QEMU's control. So we use the
* safe syscall wrapper to ensure that we either take the
* signal as a guest signal, or else it does not happen
* before the execve completes and makes it the other
* program's problem.
*/
ret = get_errno(safe_execve(p, argp, envp));
unlock_user(p, arg1, 0); unlock_user(p, arg1, 0);
goto execve_end; goto execve_end;
@ -6930,12 +7060,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break; break;
#ifdef TARGET_NR_sigreturn #ifdef TARGET_NR_sigreturn
case TARGET_NR_sigreturn: case TARGET_NR_sigreturn:
/* NOTE: ret is eax, so not transcoding must be done */
ret = do_sigreturn(cpu_env); ret = do_sigreturn(cpu_env);
break; break;
#endif #endif
case TARGET_NR_rt_sigreturn: case TARGET_NR_rt_sigreturn:
/* NOTE: ret is eax, so not transcoding must be done */
ret = do_rt_sigreturn(cpu_env); ret = do_rt_sigreturn(cpu_env);
break; break;
case TARGET_NR_sethostname: case TARGET_NR_sethostname:
@ -7124,8 +7252,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
sig_ptr = NULL; sig_ptr = NULL;
} }
ret = get_errno(sys_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr, ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
ts_ptr, sig_ptr)); ts_ptr, sig_ptr));
if (!is_error(ret)) { if (!is_error(ret)) {
if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n)) if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
@ -7694,7 +7822,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
rusage_ptr = &rusage; rusage_ptr = &rusage;
else else
rusage_ptr = NULL; rusage_ptr = NULL;
ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr)); ret = get_errno(safe_wait4(arg1, &status, arg3, rusage_ptr));
if (!is_error(ret)) { if (!is_error(ret)) {
if (status_ptr && ret) { if (status_ptr && ret) {
status = host_to_target_waitstatus(status); status = host_to_target_waitstatus(status);
@ -8740,9 +8868,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif #endif
#ifdef TARGET_NR_setresuid #ifdef TARGET_NR_setresuid
case TARGET_NR_setresuid: case TARGET_NR_setresuid:
ret = get_errno(setresuid(low2highuid(arg1), ret = get_errno(sys_setresuid(low2highuid(arg1),
low2highuid(arg2), low2highuid(arg2),
low2highuid(arg3))); low2highuid(arg3)));
break; break;
#endif #endif
#ifdef TARGET_NR_getresuid #ifdef TARGET_NR_getresuid
@ -8761,9 +8889,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif #endif
#ifdef TARGET_NR_getresgid #ifdef TARGET_NR_getresgid
case TARGET_NR_setresgid: case TARGET_NR_setresgid:
ret = get_errno(setresgid(low2highgid(arg1), ret = get_errno(sys_setresgid(low2highgid(arg1),
low2highgid(arg2), low2highgid(arg2),
low2highgid(arg3))); low2highgid(arg3)));
break; break;
#endif #endif
#ifdef TARGET_NR_getresgid #ifdef TARGET_NR_getresgid
@ -8789,10 +8917,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break; break;
#endif #endif
case TARGET_NR_setuid: case TARGET_NR_setuid:
ret = get_errno(setuid(low2highuid(arg1))); ret = get_errno(sys_setuid(low2highuid(arg1)));
break; break;
case TARGET_NR_setgid: case TARGET_NR_setgid:
ret = get_errno(setgid(low2highgid(arg1))); ret = get_errno(sys_setgid(low2highgid(arg1)));
break; break;
case TARGET_NR_setfsuid: case TARGET_NR_setfsuid:
ret = get_errno(setfsuid(arg1)); ret = get_errno(setfsuid(arg1));
@ -9074,7 +9202,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif #endif
#ifdef TARGET_NR_setresuid32 #ifdef TARGET_NR_setresuid32
case TARGET_NR_setresuid32: case TARGET_NR_setresuid32:
ret = get_errno(setresuid(arg1, arg2, arg3)); ret = get_errno(sys_setresuid(arg1, arg2, arg3));
break; break;
#endif #endif
#ifdef TARGET_NR_getresuid32 #ifdef TARGET_NR_getresuid32
@ -9093,7 +9221,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif #endif
#ifdef TARGET_NR_setresgid32 #ifdef TARGET_NR_setresgid32
case TARGET_NR_setresgid32: case TARGET_NR_setresgid32:
ret = get_errno(setresgid(arg1, arg2, arg3)); ret = get_errno(sys_setresgid(arg1, arg2, arg3));
break; break;
#endif #endif
#ifdef TARGET_NR_getresgid32 #ifdef TARGET_NR_getresgid32
@ -9120,12 +9248,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif #endif
#ifdef TARGET_NR_setuid32 #ifdef TARGET_NR_setuid32
case TARGET_NR_setuid32: case TARGET_NR_setuid32:
ret = get_errno(setuid(arg1)); ret = get_errno(sys_setuid(arg1));
break; break;
#endif #endif
#ifdef TARGET_NR_setgid32 #ifdef TARGET_NR_setgid32
case TARGET_NR_setgid32: case TARGET_NR_setgid32:
ret = get_errno(setgid(arg1)); ret = get_errno(sys_setgid(arg1));
break; break;
#endif #endif
#ifdef TARGET_NR_setfsuid32 #ifdef TARGET_NR_setfsuid32

View File

@ -55,7 +55,8 @@
#define TARGET_IOC_NRBITS 8 #define TARGET_IOC_NRBITS 8
#define TARGET_IOC_TYPEBITS 8 #define TARGET_IOC_TYPEBITS 8
#if defined(TARGET_I386) || (defined(TARGET_ARM) && defined(TARGET_ABI32)) \ #if (defined(TARGET_I386) && defined(TARGET_ABI32)) \
|| (defined(TARGET_ARM) && defined(TARGET_ABI32)) \
|| defined(TARGET_SPARC) \ || defined(TARGET_SPARC) \
|| defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS) || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS)
/* 16 bit uid wrappers emulation */ /* 16 bit uid wrappers emulation */

View File

@ -25,4 +25,5 @@ static inline abi_ulong get_sp_from_cpustate(CPUTLGState *state)
return state->regs[TILEGX_R_SP]; return state->regs[TILEGX_R_SP];
} }
#endif /* TARGET_SIGNAL_H */ #endif /* TARGET_SIGNAL_H */