From patchwork Thu Sep 22 12:13:41 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Riku Voipio X-Patchwork-Id: 76766 Delivered-To: patch@linaro.org Received: by 10.140.106.72 with SMTP id d66csp8425qgf; Thu, 22 Sep 2016 05:40:23 -0700 (PDT) X-Received: by 10.55.43.228 with SMTP id r97mr1813285qkr.201.1474548023756; Thu, 22 Sep 2016 05:40:23 -0700 (PDT) Return-Path: Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id h29si1011311qkh.34.2016.09.22.05.40.23 for (version=TLS1 cipher=AES128-SHA bits=128/128); Thu, 22 Sep 2016 05:40:23 -0700 (PDT) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom=qemu-devel-bounces+patch=linaro.org@nongnu.org; dmarc=fail (p=NONE dis=NONE) header.from=linaro.org Received: from localhost ([::1]:43163 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bn3Id-0007SQ-5m for patch@linaro.org; Thu, 22 Sep 2016 08:40:23 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53334) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bn2uV-0000J5-Kc for qemu-devel@nongnu.org; Thu, 22 Sep 2016 08:15:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bn2uP-0006je-8C for qemu-devel@nongnu.org; Thu, 22 Sep 2016 08:15:27 -0400 Received: from mail-lf0-f52.google.com ([209.85.215.52]:33285) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bn2uO-0006jG-Sl for qemu-devel@nongnu.org; Thu, 22 Sep 2016 08:15:21 -0400 Received: by mail-lf0-f52.google.com with SMTP id b71so38938591lfg.0 for ; Thu, 22 Sep 2016 05:15:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=pqf26e/k2IAV7ZCp+IFg3I2DCW7ly9nqVtnpWslxC2o=; b=VbRmgZKasqP9rdqJWe5XH7H6hyNLvGXBI4D35VlwWDmNAZ8Ld9dShYAMWtpuTQeY9t qMGqKzLzbEVLT5TuS6gUXNj8iEjCF6iB6yxF1Wk5Lp1CMTDXhSKJnb9LVHjPFaWREAO6 ZWAVrnygsUQBoE+VeSA3F1v0suWRRVEiLQDps= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=pqf26e/k2IAV7ZCp+IFg3I2DCW7ly9nqVtnpWslxC2o=; b=aHCQQnI2qAcQWR7i+4CGwmdh9Hm5UCOSDK8XOVEoUSN+wDl0mwuyjwQxbczwp8BV8Q m0th0n3IT/7UIg/W3IZD83lmuuCKmGOZN3zblnlGJfY+ApgKuRWuozRTz2qfuQWPMZ9w xDoulERFc1hdiXoGZQM+OEOC75scmqN5kj6AaUfcWv64JNrt/pJ7wyu9AgOD4UB1jzRS GWy7vEF/z26hQgBYsjnEnF92WB88O3jiZpy8J0lVGHcKyVUhnUmR5Alja3bp1Q1hRf5H KxM1GEBXjn7eSaFRGCe21Bu7iw9mW9eml5FYxZUAImlM9kSxO50TIvUqW+GE7lT1/eL3 LJ9A== X-Gm-Message-State: AE9vXwMYUDelGDOqMc1iBwII2ZQtaDJPLLa+UuWSFOQlVIkBc7NSbF2BW97aZT1SXYS5vgAe X-Received: by 10.25.18.18 with SMTP id h18mr750911lfi.115.1474546460091; Thu, 22 Sep 2016 05:14:20 -0700 (PDT) Received: from beaming.home (91-157-170-157.elisa-laajakaista.fi. [91.157.170.157]) by smtp.gmail.com with ESMTPSA id u14sm294378lja.11.2016.09.22.05.14.19 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 22 Sep 2016 05:14:19 -0700 (PDT) From: riku.voipio@linaro.org To: qemu-devel@nongnu.org Date: Thu, 22 Sep 2016 15:13:41 +0300 Message-Id: X-Mailer: git-send-email 2.1.4 In-Reply-To: References: X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.85.215.52 Subject: [Qemu-devel] [PULL 21/26] linux-user: SIGSEGV from sigreturn need not be fatal X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" From: Peter Maydell 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 Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/signal.c | 81 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 27 deletions(-) -- 2.1.4 diff --git a/linux-user/signal.c b/linux-user/signal.c index 4383696..60fda18 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -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)) /* 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) { /* 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; } @@ -540,7 +561,7 @@ static void force_sigsegv(int oldsig) #endif /* 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; CPUArchState *env = cpu->env_ptr; @@ -1181,7 +1202,7 @@ long do_sigreturn(CPUX86State *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUX86State *env) @@ -1212,7 +1233,7 @@ long do_rt_sigreturn(CPUX86State *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_AARCH64) @@ -1482,7 +1503,7 @@ long do_rt_sigreturn(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_sigreturn(CPUARMState *env) @@ -2004,8 +2025,8 @@ static long do_sigreturn_v1(CPUARMState *env) return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } static abi_ulong *restore_sigframe_v2_vfp(CPUARMState *env, abi_ulong *regspace) @@ -2131,8 +2152,8 @@ static long do_sigreturn_v2(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_sigreturn(CPUARMState *env) @@ -2185,8 +2206,8 @@ static long do_rt_sigreturn_v1(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } static long do_rt_sigreturn_v2(CPUARMState *env) @@ -2218,8 +2239,8 @@ static long do_rt_sigreturn_v2(CPUARMState *env) badframe: unlock_user_struct(frame, frame_addr, 0); - force_sig(TARGET_SIGSEGV /* , current */); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUARMState *env) @@ -2553,6 +2574,7 @@ long do_sigreturn(CPUSPARCState *env) segv_and_exit: unlock_user_struct(sf, sf_addr, 0); force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUSPARCState *env) @@ -3110,8 +3132,8 @@ long do_sigreturn(CPUMIPSState *regs) return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV/*, current*/); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } # endif /* O32 */ @@ -3207,8 +3229,8 @@ long do_rt_sigreturn(CPUMIPSState *env) return -TARGET_QEMU_ESIGRETURN; badframe: - force_sig(TARGET_SIGSEGV/*, current*/); - return 0; + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_SH4) @@ -3474,7 +3496,7 @@ long do_sigreturn(CPUSH4State *regs) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUSH4State *regs) @@ -3506,7 +3528,7 @@ long do_rt_sigreturn(CPUSH4State *regs) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_MICROBLAZE) @@ -3725,6 +3747,7 @@ long do_sigreturn(CPUMBState *env) return -TARGET_QEMU_ESIGRETURN; badframe: force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUMBState *env) @@ -3892,6 +3915,7 @@ long do_sigreturn(CPUCRISState *env) return -TARGET_QEMU_ESIGRETURN; badframe: force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUCRISState *env) @@ -4383,7 +4407,7 @@ long do_sigreturn(CPUS390XState *env) badframe: force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUS390XState *env) @@ -4414,7 +4438,7 @@ long do_rt_sigreturn(CPUS390XState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_PPC) @@ -4973,7 +4997,7 @@ sigsegv: unlock_user_struct(sr, sr_addr, 1); unlock_user_struct(sc, sc_addr, 1); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } /* See arch/powerpc/kernel/signal_32.c. */ @@ -5028,7 +5052,7 @@ long do_rt_sigreturn(CPUPPCState *env) sigsegv: unlock_user_struct(rt_sf, rt_sf_addr, 1); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_M68K) @@ -5358,7 +5382,7 @@ long do_sigreturn(CPUM68KState *env) badframe: force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUM68KState *env) @@ -5391,7 +5415,7 @@ long do_rt_sigreturn(CPUM68KState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); - return 0; + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_ALPHA) @@ -5620,6 +5644,7 @@ long do_sigreturn(CPUAlphaState *env) badframe: force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } long do_rt_sigreturn(CPUAlphaState *env) @@ -5649,6 +5674,7 @@ long do_rt_sigreturn(CPUAlphaState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } #elif defined(TARGET_TILEGX) @@ -5813,6 +5839,7 @@ long do_rt_sigreturn(CPUTLGState *env) badframe: unlock_user_struct(frame, frame_addr, 0); force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; } #else @@ -5879,12 +5906,12 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig, sig != TARGET_SIGURG && sig != TARGET_SIGWINCH && sig != TARGET_SIGCONT) { - force_sig(sig); + dump_core_and_abort(sig); } } else if (handler == TARGET_SIG_IGN) { /* ignore sig */ } else if (handler == TARGET_SIG_ERR) { - force_sig(sig); + dump_core_and_abort(sig); } else { /* compute the blocked signals during the handler execution */ sigset_t *blocked_set;