linux-user: SIGSEGV from sigreturn need not be fatal
If the sigreturn syscall fails to read memory then this causes a SIGSEGV, but this is not necessarily a fatal signal -- the guest process can catch it. We don't implement this correctly because the behaviour of QEMU's force_sig() function has drifted away from the kernel function of the same name -- ours now does "always do a guest core dump and abort execution", whereas the kernel version simply forces the guest to take a signal, which may or may not eventually cause a core dump. Rename our force_sig() to dump_core_and_abort(), and provide a force_sig() which acts more like the kernel version as the sigreturn implementations expect it to. Since force_sig() now returns, we must update all the callsites to return -TARGET_QEMU_ESIGRETURN so that the main loop doesn't change the guest registers before the signal handler is invoked. Reviewed-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
This commit is contained in:
parent
28298c912e
commit
c599d4d6d6
@ -512,6 +512,27 @@ void signal_init(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(TARGET_OPENRISC) && !defined(TARGET_UNICORE32) && \
|
||||||
|
!defined(TARGET_X86_64)
|
||||||
|
/* Force a synchronously taken signal. The kernel force_sig() function
|
||||||
|
* also forces the signal to "not blocked, not ignored", but for QEMU
|
||||||
|
* that work is done in process_pending_signals().
|
||||||
|
*/
|
||||||
|
static void force_sig(int sig)
|
||||||
|
{
|
||||||
|
CPUState *cpu = thread_cpu;
|
||||||
|
CPUArchState *env = cpu->env_ptr;
|
||||||
|
target_siginfo_t info;
|
||||||
|
|
||||||
|
info.si_signo = sig;
|
||||||
|
info.si_errno = 0;
|
||||||
|
info.si_code = TARGET_SI_KERNEL;
|
||||||
|
info._sifields._kill._pid = 0;
|
||||||
|
info._sifields._kill._uid = 0;
|
||||||
|
queue_signal(env, info.si_signo, QEMU_SI_KILL, &info);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !(defined(TARGET_X86_64) || defined(TARGET_UNICORE32))
|
#if !(defined(TARGET_X86_64) || defined(TARGET_UNICORE32))
|
||||||
|
|
||||||
/* Force a SIGSEGV if we couldn't write to memory trying to set
|
/* Force a SIGSEGV if we couldn't write to memory trying to set
|
||||||
@ -526,7 +547,7 @@ static void force_sigsegv(int oldsig)
|
|||||||
|
|
||||||
if (oldsig == SIGSEGV) {
|
if (oldsig == SIGSEGV) {
|
||||||
/* Make sure we don't try to deliver the signal again; this will
|
/* Make sure we don't try to deliver the signal again; this will
|
||||||
* end up with handle_pending_signal() calling force_sig().
|
* end up with handle_pending_signal() calling dump_core_and_abort().
|
||||||
*/
|
*/
|
||||||
sigact_table[oldsig - 1]._sa_handler = TARGET_SIG_DFL;
|
sigact_table[oldsig - 1]._sa_handler = TARGET_SIG_DFL;
|
||||||
}
|
}
|
||||||
@ -540,7 +561,7 @@ static void force_sigsegv(int oldsig)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* abort execution with signal */
|
/* abort execution with signal */
|
||||||
static void QEMU_NORETURN force_sig(int target_sig)
|
static void QEMU_NORETURN dump_core_and_abort(int target_sig)
|
||||||
{
|
{
|
||||||
CPUState *cpu = thread_cpu;
|
CPUState *cpu = thread_cpu;
|
||||||
CPUArchState *env = cpu->env_ptr;
|
CPUArchState *env = cpu->env_ptr;
|
||||||
@ -1181,7 +1202,7 @@ long do_sigreturn(CPUX86State *env)
|
|||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUX86State *env)
|
long do_rt_sigreturn(CPUX86State *env)
|
||||||
@ -1212,7 +1233,7 @@ long do_rt_sigreturn(CPUX86State *env)
|
|||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(TARGET_AARCH64)
|
#elif defined(TARGET_AARCH64)
|
||||||
@ -1482,7 +1503,7 @@ long do_rt_sigreturn(CPUARMState *env)
|
|||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_sigreturn(CPUARMState *env)
|
long do_sigreturn(CPUARMState *env)
|
||||||
@ -2004,8 +2025,8 @@ static long do_sigreturn_v1(CPUARMState *env)
|
|||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(TARGET_SIGSEGV /* , current */);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
|
static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace)
|
||||||
@ -2131,8 +2152,8 @@ static long do_sigreturn_v2(CPUARMState *env)
|
|||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV /* , current */);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_sigreturn(CPUARMState *env)
|
long do_sigreturn(CPUARMState *env)
|
||||||
@ -2185,8 +2206,8 @@ static long do_rt_sigreturn_v1(CPUARMState *env)
|
|||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV /* , current */);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long do_rt_sigreturn_v2(CPUARMState *env)
|
static long do_rt_sigreturn_v2(CPUARMState *env)
|
||||||
@ -2218,8 +2239,8 @@ static long do_rt_sigreturn_v2(CPUARMState *env)
|
|||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV /* , current */);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUARMState *env)
|
long do_rt_sigreturn(CPUARMState *env)
|
||||||
@ -2553,6 +2574,7 @@ long do_sigreturn(CPUSPARCState *env)
|
|||||||
segv_and_exit:
|
segv_and_exit:
|
||||||
unlock_user_struct(sf, sf_addr, 0);
|
unlock_user_struct(sf, sf_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUSPARCState *env)
|
long do_rt_sigreturn(CPUSPARCState *env)
|
||||||
@ -3110,8 +3132,8 @@ long do_sigreturn(CPUMIPSState *regs)
|
|||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(TARGET_SIGSEGV/*, current*/);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
# endif /* O32 */
|
# endif /* O32 */
|
||||||
|
|
||||||
@ -3207,8 +3229,8 @@ long do_rt_sigreturn(CPUMIPSState *env)
|
|||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(TARGET_SIGSEGV/*, current*/);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(TARGET_SH4)
|
#elif defined(TARGET_SH4)
|
||||||
@ -3474,7 +3496,7 @@ long do_sigreturn(CPUSH4State *regs)
|
|||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUSH4State *regs)
|
long do_rt_sigreturn(CPUSH4State *regs)
|
||||||
@ -3506,7 +3528,7 @@ long do_rt_sigreturn(CPUSH4State *regs)
|
|||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
#elif defined(TARGET_MICROBLAZE)
|
#elif defined(TARGET_MICROBLAZE)
|
||||||
|
|
||||||
@ -3725,6 +3747,7 @@ long do_sigreturn(CPUMBState *env)
|
|||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUMBState *env)
|
long do_rt_sigreturn(CPUMBState *env)
|
||||||
@ -3892,6 +3915,7 @@ long do_sigreturn(CPUCRISState *env)
|
|||||||
return -TARGET_QEMU_ESIGRETURN;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUCRISState *env)
|
long do_rt_sigreturn(CPUCRISState *env)
|
||||||
@ -4383,7 +4407,7 @@ long do_sigreturn(CPUS390XState *env)
|
|||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUS390XState *env)
|
long do_rt_sigreturn(CPUS390XState *env)
|
||||||
@ -4414,7 +4438,7 @@ long do_rt_sigreturn(CPUS390XState *env)
|
|||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(TARGET_PPC)
|
#elif defined(TARGET_PPC)
|
||||||
@ -4973,7 +4997,7 @@ sigsegv:
|
|||||||
unlock_user_struct(sr, sr_addr, 1);
|
unlock_user_struct(sr, sr_addr, 1);
|
||||||
unlock_user_struct(sc, sc_addr, 1);
|
unlock_user_struct(sc, sc_addr, 1);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See arch/powerpc/kernel/signal_32.c. */
|
/* See arch/powerpc/kernel/signal_32.c. */
|
||||||
@ -5028,7 +5052,7 @@ long do_rt_sigreturn(CPUPPCState *env)
|
|||||||
sigsegv:
|
sigsegv:
|
||||||
unlock_user_struct(rt_sf, rt_sf_addr, 1);
|
unlock_user_struct(rt_sf, rt_sf_addr, 1);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(TARGET_M68K)
|
#elif defined(TARGET_M68K)
|
||||||
@ -5358,7 +5382,7 @@ long do_sigreturn(CPUM68KState *env)
|
|||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUM68KState *env)
|
long do_rt_sigreturn(CPUM68KState *env)
|
||||||
@ -5391,7 +5415,7 @@ long do_rt_sigreturn(CPUM68KState *env)
|
|||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
return 0;
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(TARGET_ALPHA)
|
#elif defined(TARGET_ALPHA)
|
||||||
@ -5620,6 +5644,7 @@ long do_sigreturn(CPUAlphaState *env)
|
|||||||
|
|
||||||
badframe:
|
badframe:
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
long do_rt_sigreturn(CPUAlphaState *env)
|
long do_rt_sigreturn(CPUAlphaState *env)
|
||||||
@ -5649,6 +5674,7 @@ long do_rt_sigreturn(CPUAlphaState *env)
|
|||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(TARGET_TILEGX)
|
#elif defined(TARGET_TILEGX)
|
||||||
@ -5813,6 +5839,7 @@ long do_rt_sigreturn(CPUTLGState *env)
|
|||||||
badframe:
|
badframe:
|
||||||
unlock_user_struct(frame, frame_addr, 0);
|
unlock_user_struct(frame, frame_addr, 0);
|
||||||
force_sig(TARGET_SIGSEGV);
|
force_sig(TARGET_SIGSEGV);
|
||||||
|
return -TARGET_QEMU_ESIGRETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -5879,12 +5906,12 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
|
|||||||
sig != TARGET_SIGURG &&
|
sig != TARGET_SIGURG &&
|
||||||
sig != TARGET_SIGWINCH &&
|
sig != TARGET_SIGWINCH &&
|
||||||
sig != TARGET_SIGCONT) {
|
sig != TARGET_SIGCONT) {
|
||||||
force_sig(sig);
|
dump_core_and_abort(sig);
|
||||||
}
|
}
|
||||||
} else if (handler == TARGET_SIG_IGN) {
|
} else if (handler == TARGET_SIG_IGN) {
|
||||||
/* ignore sig */
|
/* ignore sig */
|
||||||
} else if (handler == TARGET_SIG_ERR) {
|
} else if (handler == TARGET_SIG_ERR) {
|
||||||
force_sig(sig);
|
dump_core_and_abort(sig);
|
||||||
} else {
|
} else {
|
||||||
/* compute the blocked signals during the handler execution */
|
/* compute the blocked signals during the handler execution */
|
||||||
sigset_t *blocked_set;
|
sigset_t *blocked_set;
|
||||||
|
Loading…
Reference in New Issue
Block a user