From: Richard Henderson <richard.henderson@linaro.org>
To: qemu-devel@nongnu.org
Subject: [PATCH v3 59/66] accel/tcg: Handle SIGBUS in handle_cpu_signal
Date: Wed, 18 Aug 2021 09:19:13 -1000 [thread overview]
Message-ID: <20210818191920.390759-60-richard.henderson@linaro.org> (raw)
In-Reply-To: <20210818191920.390759-1-richard.henderson@linaro.org>
We've been registering host SIGBUS, but then treating it
exactly like SIGSEGV.
Handle BUS_ADRALN via cpu_unaligned_access, but allow other
SIGBUS si_codes to continue into the host-to-guest signal
coversion code in host_signal_handler. Unwind the guest
state so that we report the correct guest PC for the fault.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
accel/tcg/user-exec.c | 188 +++++++++++++++++++++++++++--------------
linux-user/signal.c | 36 +++++---
accel/tcg/trace-events | 3 +-
3 files changed, 152 insertions(+), 75 deletions(-)
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index 1c9486c76d..c7ee5accb3 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -57,17 +57,123 @@ static void QEMU_NORETURN cpu_exit_tb_from_sighandler(CPUState *cpu,
cpu_loop_exit_noexc(cpu);
}
-/* 'pc' is the host PC at which the exception was raised. 'address' is
- the effective address of the memory exception. 'is_write' is 1 if a
- write caused the exception and otherwise 0'. 'old_set' is the
- signal set which should be restored */
-static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
- int is_write, sigset_t *old_set)
+static bool handle_cpu_sigsegv(CPUState *cpu, uintptr_t pc, uintptr_t addr,
+ int si_code, MMUAccessType access_type,
+ sigset_t *old_set)
+{
+ trace_sigsegv(pc, addr, access_type, *(unsigned long *)old_set);
+
+ /* XXX: locking issue */
+ /*
+ * Note that it is important that we don't call page_unprotect() unless
+ * this is really a "write to nonwriteable page" fault, because
+ * page_unprotect() assumes that if it is called for an access to
+ * a page that's writeable this means we had two threads racing and
+ * another thread got there first and already made the page writeable;
+ * so we will retry the access. If we were to call page_unprotect()
+ * for some other kind of fault that should really be passed to the
+ * guest, we'd end up in an infinite loop of retrying the faulting
+ * access.
+ */
+ if (access_type == MMU_DATA_STORE
+ && si_code == SEGV_ACCERR
+ && h2g_valid(addr)) {
+ switch (page_unprotect(h2g_nocheck(addr), pc)) {
+ case 0:
+ /*
+ * Fault not caused by a page marked unwritable to protect
+ * cached translations, must be the guest binary's problem.
+ */
+ break;
+ case 1:
+ /*
+ * Fault caused by protection of cached translation; TBs
+ * invalidated, so resume execution. Retain helper_retaddr
+ * for a possible second fault.
+ */
+ return true;
+ case 2:
+ /*
+ * Fault caused by protection of cached translation, and the
+ * currently executing TB was modified and must be exited
+ * immediately. Clear helper_retaddr for next execution.
+ */
+ clear_helper_retaddr();
+ cpu_exit_tb_from_sighandler(cpu, old_set);
+ /* NORETURN */
+ default:
+ g_assert_not_reached();
+ }
+ }
+
+ /*
+ * Convert forcefully to guest address space, invalid addresses
+ * are still valid segv ones.
+ */
+ addr = h2g_nocheck(addr);
+
+ /*
+ * There is no way the target can handle this other than raising
+ * an exception. Undo signal and retaddr state prior to longjmp.
+ */
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ clear_helper_retaddr();
+
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+ cc->tcg_ops->tlb_fill(cpu, addr, 0, access_type, MMU_USER_IDX, false, pc);
+ g_assert_not_reached();
+}
+
+static bool handle_cpu_sigbus(CPUState *cpu, uintptr_t pc, uintptr_t addr,
+ int si_code, MMUAccessType access_type,
+ sigset_t *old_set)
+{
+ trace_sigbus(pc, addr, access_type, *(unsigned long *)old_set);
+
+ if (si_code == BUS_ADRALN) {
+ /*
+ * We're expecting host alignment faults to correspond
+ * directly to guest alignment faults, and thus the host
+ * address must correspond to a guest address.
+ */
+ addr = h2g(addr);
+
+ /* Undo signal and retaddr state prior to longjmp. */
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ clear_helper_retaddr();
+
+ cpu_unaligned_access(cpu, addr, access_type, MMU_USER_IDX, pc);
+ }
+
+ /*
+ * Otherwise this is probably BUS_ADRERR or suchlike, which
+ * can be easily triggered by the guest playing with mmap
+ * and accessing past the end of the file.
+ *
+ * Use PC to unwind to the current guest address and then
+ * return false to pass on the host signal to the guest.
+ */
+ cpu_restore_state(cpu, pc, true);
+ return false;
+}
+
+/**
+ * handle_cpu_signal:
+ * @pc: the host PC at which the exception was raised,
+ * @address: the effective address of the memory exception,
+ * @is_write: true if a write caused the exception,
+ * @old_set: signal set which should be restored.
+ *
+ * Return true if the signal has been handled by the vcpu,
+ * false if the signal should be sent on to the guest.
+ */
+static bool handle_cpu_signal(uintptr_t pc, siginfo_t *info,
+ bool is_write, sigset_t *old_set)
{
CPUState *cpu = current_cpu;
- CPUClass *cc;
- unsigned long address = (unsigned long)info->si_addr;
+ uintptr_t addr = (uintptr_t)info->si_addr;
MMUAccessType access_type = is_write ? MMU_DATA_STORE : MMU_DATA_LOAD;
+ int code;
switch (helper_retaddr) {
default:
@@ -119,7 +225,8 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
break;
}
- /* For synchronous signals we expect to be coming from the vCPU
+ /*
+ * For synchronous signals we expect to be coming from the vCPU
* thread (so current_cpu should be valid) and either from running
* code or during translation which can fault as we cross pages.
*
@@ -132,62 +239,15 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
abort();
}
- trace_sigsegv(pc, address, is_write, *(unsigned long *)old_set);
-
- /* XXX: locking issue */
- /* Note that it is important that we don't call page_unprotect() unless
- * this is really a "write to nonwriteable page" fault, because
- * page_unprotect() assumes that if it is called for an access to
- * a page that's writeable this means we had two threads racing and
- * another thread got there first and already made the page writeable;
- * so we will retry the access. If we were to call page_unprotect()
- * for some other kind of fault that should really be passed to the
- * guest, we'd end up in an infinite loop of retrying the faulting
- * access.
- */
- if (is_write && info->si_signo == SIGSEGV && info->si_code == SEGV_ACCERR &&
- h2g_valid(address)) {
- switch (page_unprotect(h2g(address), pc)) {
- case 0:
- /* Fault not caused by a page marked unwritable to protect
- * cached translations, must be the guest binary's problem.
- */
- break;
- case 1:
- /* Fault caused by protection of cached translation; TBs
- * invalidated, so resume execution. Retain helper_retaddr
- * for a possible second fault.
- */
- return 1;
- case 2:
- /* Fault caused by protection of cached translation, and the
- * currently executing TB was modified and must be exited
- * immediately. Clear helper_retaddr for next execution.
- */
- clear_helper_retaddr();
- cpu_exit_tb_from_sighandler(cpu, old_set);
- /* NORETURN */
-
- default:
- g_assert_not_reached();
- }
+ code = info->si_code;
+ switch (info->si_signo) {
+ case SIGSEGV:
+ return handle_cpu_sigsegv(cpu, pc, addr, code, access_type, old_set);
+ case SIGBUS:
+ return handle_cpu_sigbus(cpu, pc, addr, code, access_type, old_set);
+ default:
+ g_assert_not_reached();
}
-
- /* Convert forcefully to guest address space, invalid addresses
- are still valid segv ones */
- address = h2g_nocheck(address);
-
- /*
- * There is no way the target can handle this other than raising
- * an exception. Undo signal and retaddr state prior to longjmp.
- */
- sigprocmask(SIG_SETMASK, old_set, NULL);
- clear_helper_retaddr();
-
- cc = CPU_GET_CLASS(cpu);
- cc->tcg_ops->tlb_fill(cpu, address, 0, access_type,
- MMU_USER_IDX, false, pc);
- g_assert_not_reached();
}
static int probe_access_internal(CPUArchState *env, target_ulong addr,
diff --git a/linux-user/signal.c b/linux-user/signal.c
index a8faea6f09..99b456a781 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -747,27 +747,37 @@ static inline void rewind_if_in_safe_syscall(void *puc)
static void host_signal_handler(int host_signum, siginfo_t *info,
void *puc)
{
- CPUArchState *env = thread_cpu->env_ptr;
- CPUState *cpu = env_cpu(env);
+ CPUState *cpu = thread_cpu;
+ CPUArchState *env = cpu->env_ptr;
TaskState *ts = cpu->opaque;
-
int sig;
target_siginfo_t tinfo;
ucontext_t *uc = puc;
struct emulated_sigtable *k;
+ bool must_exit = false;
- /* the CPU emulator uses some host signals to detect exceptions,
- we forward to it some signals */
+ /*
+ * The CPU emulator uses some host signals to detect exceptions,
+ * we forward to it some signals.
+ */
if ((host_signum == SIGSEGV || host_signum == SIGBUS)
&& info->si_code > 0) {
- if (cpu_signal_handler(host_signum, info, puc))
+ if (cpu_signal_handler(host_signum, info, puc)) {
return;
+ }
+ /*
+ * E.g. SIGBUS, without BUS_ADRALN, which we want to pass on.
+ * We have unwound the TB to PC, so must use cpu_loop_exit below.
+ */
+ must_exit = true;
}
/* get target signal number */
sig = host_to_target_signal(host_signum);
- if (sig < 1 || sig > TARGET_NSIG)
+ if (sig < 1 || sig > TARGET_NSIG) {
+ assert(!must_exit);
return;
+ }
trace_user_host_signal(env, host_signum, sig);
rewind_if_in_safe_syscall(puc);
@@ -778,7 +788,8 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
k->pending = sig;
ts->signal_pending = 1;
- /* Block host signals until target signal handler entered. We
+ /*
+ * Block host signals until target signal handler entered. We
* can't block SIGSEGV or SIGBUS while we're executing guest
* code in case the guest code provokes one in the window between
* now and it getting out to the main loop. Signals will be
@@ -796,8 +807,13 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
sigdelset(&uc->uc_sigmask, SIGSEGV);
sigdelset(&uc->uc_sigmask, SIGBUS);
- /* interrupt the virtual CPU as soon as possible */
- cpu_exit(thread_cpu);
+ /* Interrupt the virtual CPU as soon as possible. */
+ if (must_exit) {
+ cpu->exception_index = EXCP_INTERRUPT;
+ cpu_loop_exit(cpu);
+ } else {
+ cpu_exit(cpu);
+ }
}
/* do_sigaltstack() returns target values and errnos. */
diff --git a/accel/tcg/trace-events b/accel/tcg/trace-events
index d54416f2ee..009fbdc124 100644
--- a/accel/tcg/trace-events
+++ b/accel/tcg/trace-events
@@ -10,4 +10,5 @@ exec_tb_exit(void *last_tb, unsigned int flags) "tb:%p flags=0x%x"
translate_block(void *tb, uintptr_t pc, const void *tb_code) "tb:%p, pc:0x%"PRIxPTR", tb_code:%p"
# user-exec.c
-sigsegv(uintptr_t pc, uintptr_t addr, int is_write, unsigned long old_set) "pc:0x%"PRIxPTR", addr:0x%"PRIxPTR", w:%d, oldset:0x%lx"
+sigsegv(uintptr_t pc, uintptr_t addr, int access_type, unsigned long old_set) "pc:0x%"PRIxPTR", addr:0x%"PRIxPTR", at:%d, oldset:0x%lx"
+sigbus(uintptr_t pc, uintptr_t addr, int access_type, unsigned long old_set) "pc:0x%"PRIxPTR", addr:0x%"PRIxPTR", at:%d, oldset:0x%lx"
--
2.25.1
next prev parent reply other threads:[~2021-08-18 20:13 UTC|newest]
Thread overview: 108+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-18 19:18 [PATCH v3 00/66] Unaligned access for user-only Richard Henderson
2021-08-18 19:18 ` [PATCH v3 01/66] util: Suppress -Wstringop-overflow in qemu_thread_start Richard Henderson
2021-08-19 15:13 ` Peter Maydell
2021-08-18 19:18 ` [PATCH v3 02/66] hw/core: Make do_unaligned_access noreturn Richard Henderson
2021-08-19 6:15 ` Alistair Francis
2021-08-18 19:18 ` [PATCH v3 03/66] hw/core: Make do_unaligned_access available to user-only Richard Henderson
2021-08-18 19:18 ` [PATCH v3 04/66] target/alpha: Implement do_unaligned_access for user-only Richard Henderson
2021-08-18 19:18 ` [PATCH v3 05/66] target/arm: " Richard Henderson
2021-08-18 19:18 ` [PATCH v3 06/66] target/hppa: " Richard Henderson
2021-08-19 15:32 ` Peter Maydell
2021-08-18 19:18 ` [PATCH v3 07/66] target/microblaze: Do not set MO_ALIGN " Richard Henderson
2021-08-18 19:18 ` [PATCH v3 08/66] target/mips: Implement do_unaligned_access " Richard Henderson
2021-08-19 15:34 ` Peter Maydell
2021-08-18 19:18 ` [PATCH v3 09/66] target/ppc: Move SPR_DSISR setting to powerpc_excp Richard Henderson
2021-08-19 15:39 ` Peter Maydell
2021-08-19 19:13 ` Richard Henderson
2021-08-18 19:18 ` [PATCH v3 10/66] target/ppc: Set fault address in ppc_cpu_do_unaligned_access Richard Henderson
2021-08-19 15:41 ` Peter Maydell
2021-08-18 19:18 ` [PATCH v3 11/66] target/ppc: Implement do_unaligned_access for user-only Richard Henderson
2021-08-19 15:44 ` Peter Maydell
2021-08-18 19:18 ` [PATCH v3 12/66] target/riscv: " Richard Henderson
2021-08-18 19:18 ` [PATCH v3 13/66] target/s390x: " Richard Henderson
2021-08-18 19:18 ` [PATCH v3 14/66] target/sh4: Set fault address in superh_cpu_do_unaligned_access Richard Henderson
2021-08-18 19:18 ` [PATCH v3 15/66] target/sh4: Implement do_unaligned_access for user-only Richard Henderson
2021-08-19 15:46 ` Peter Maydell
2021-08-19 19:21 ` Richard Henderson
2021-08-18 19:18 ` [PATCH v3 16/66] target/sparc: Remove DEBUG_UNALIGNED Richard Henderson
2021-08-18 19:18 ` [PATCH v3 17/66] target/sparc: Split out build_sfsr Richard Henderson
2021-08-18 19:18 ` [PATCH v3 18/66] target/sparc: Set fault address in sparc_cpu_do_unaligned_access Richard Henderson
2021-08-18 19:18 ` [PATCH v3 19/66] target/sparc: Implement do_unaligned_access for user-only Richard Henderson
2021-08-18 19:18 ` [PATCH v3 20/66] target/xtensa: " Richard Henderson
2021-08-18 19:18 ` [PATCH v3 21/66] accel/tcg: Report unaligned atomics " Richard Henderson
2021-08-18 19:18 ` [PATCH v3 22/66] accel/tcg: Drop signness in tracing in cputlb.c Richard Henderson
2021-08-18 21:14 ` Philippe Mathieu-Daudé
2021-08-18 19:18 ` [PATCH v3 23/66] tcg: Expand MO_SIZE to 3 bits Richard Henderson
2021-08-19 6:17 ` Alistair Francis
2021-08-18 19:18 ` [PATCH v3 24/66] tcg: Rename TCGMemOpIdx to MemOpIdx Richard Henderson
2021-08-19 6:17 ` Alistair Francis
2021-08-18 19:18 ` [PATCH v3 25/66] tcg: Split out MemOpIdx to exec/memopidx.h Richard Henderson
2021-08-18 19:18 ` [PATCH v3 26/66] trace/mem: Pass MemOpIdx to trace_mem_get_info Richard Henderson
2021-08-19 15:49 ` Peter Maydell
2021-08-18 19:18 ` [PATCH v3 27/66] accel/tcg: Pass MemOpIdx to atomic_trace_*_post Richard Henderson
2021-08-18 19:18 ` [PATCH v3 28/66] plugins: Reorg arguments to qemu_plugin_vcpu_mem_cb Richard Henderson
2021-08-30 21:42 ` Philippe Mathieu-Daudé
2021-08-18 19:18 ` [PATCH v3 29/66] trace: Split guest_mem_before Richard Henderson
2021-08-18 19:18 ` [PATCH v3 30/66] target/arm: Use MO_128 for 16 byte atomics Richard Henderson
2021-08-18 19:18 ` [PATCH v3 31/66] target/i386: " Richard Henderson
2021-08-18 19:18 ` [PATCH v3 32/66] target/ppc: " Richard Henderson
2021-08-18 19:18 ` [PATCH v3 33/66] target/s390x: " Richard Henderson
2021-08-18 19:18 ` [PATCH v3 34/66] target/hexagon: Implement cpu_mmu_index Richard Henderson
2021-08-18 19:18 ` [PATCH v3 35/66] accel/tcg: Add cpu_{ld,st}*_mmu interfaces Richard Henderson
2021-08-19 15:57 ` Peter Maydell
2021-08-18 19:18 ` [PATCH v3 36/66] accel/tcg: Move cpu_atomic decls to exec/cpu_ldst.h Richard Henderson
2021-08-18 19:18 ` [PATCH v3 37/66] target/mips: Use cpu_*_data_ra for msa load/store Richard Henderson
2021-08-18 19:18 ` [PATCH v3 38/66] target/mips: Use 8-byte memory ops " Richard Henderson
2021-08-18 19:18 ` [PATCH v3 39/66] target/s390x: Use cpu_*_mmu instead of helper_*_mmu Richard Henderson
2021-08-18 19:18 ` [PATCH v3 40/66] target/sparc: " Richard Henderson
2021-08-18 19:18 ` [PATCH v3 41/66] target/arm: " Richard Henderson
2021-08-18 19:18 ` [PATCH v3 42/66] tcg: Move helper_*_mmu decls to tcg/tcg-ldst.h Richard Henderson
2021-08-18 19:18 ` [PATCH v3 43/66] tcg: Add helper_unaligned_{ld, st} for user-only sigbus Richard Henderson
2021-08-19 15:58 ` Peter Maydell
2021-08-18 19:18 ` [PATCH v3 44/66] tcg/i386: Support raising sigbus for user-only Richard Henderson
2021-08-19 16:02 ` Peter Maydell
2021-08-18 19:18 ` [PATCH v3 45/66] tests/tcg/multiarch: Add sigbus.c Richard Henderson
2021-08-19 16:04 ` Peter Maydell
2021-08-18 19:19 ` [PATCH v3 46/66] linux-user: Split out do_prctl and subroutines Richard Henderson
2021-08-19 16:06 ` Peter Maydell
2021-08-19 19:30 ` Richard Henderson
2021-08-18 19:19 ` [PATCH v3 47/66] linux-user: Disable more prctl subcodes Richard Henderson
2021-08-18 19:19 ` [PATCH v3 48/66] hw/core/cpu: Re-sort the non-pointers to the end of CPUClass Richard Henderson
2021-08-18 21:17 ` Philippe Mathieu-Daudé
2021-08-18 19:19 ` [PATCH v3 49/66] linux-user: Add code for PR_GET/SET_UNALIGN Richard Henderson
2021-08-18 19:19 ` [PATCH v3 50/66] hw/core/cpu: Move cpu properties to cpu-sysemu.c Richard Henderson
2021-08-19 15:26 ` Peter Maydell
2021-08-19 16:52 ` Eduardo Habkost
2021-08-18 19:19 ` [PATCH v3 51/66] hw/core/cpu: Add prctl-unalign-sigbus property for user-only Richard Henderson
2021-08-18 19:19 ` [PATCH v3 52/66] target/alpha: Reorg fp memory operations Richard Henderson
2021-08-18 21:21 ` Philippe Mathieu-Daudé
2021-08-18 19:19 ` [PATCH v3 53/66] target/alpha: Reorg integer " Richard Henderson
2021-08-20 9:29 ` Peter Maydell
2021-08-18 19:19 ` [PATCH v3 54/66] target/alpha: Implement prctl_unalign_sigbus Richard Henderson
2021-08-18 19:19 ` [PATCH v3 55/66] target/hppa: " Richard Henderson
2021-08-18 19:19 ` [PATCH v3 56/66] target/sh4: " Richard Henderson
2021-08-18 19:19 ` [PATCH v3 57/66] accel/tcg/user-exec: Convert DEBUG_SIGNAL to tracepoint Richard Henderson
2021-08-18 21:22 ` Philippe Mathieu-Daudé
2021-08-18 19:19 ` [PATCH v3 58/66] include/exec: Move cpu_signal_handler declaration Richard Henderson
2021-08-18 21:23 ` Philippe Mathieu-Daudé
2021-08-19 6:18 ` Alistair Francis
2021-08-18 19:19 ` Richard Henderson [this message]
2021-08-20 9:34 ` [PATCH v3 59/66] accel/tcg: Handle SIGBUS in handle_cpu_signal Peter Maydell
2021-08-22 7:48 ` Richard Henderson
2021-08-18 19:19 ` [PATCH v3 60/66] tcg/aarch64: Support raising sigbus for user-only Richard Henderson
2021-08-20 9:46 ` Peter Maydell
2021-08-18 19:19 ` [PATCH v3 61/66] tcg/ppc: " Richard Henderson
2021-08-20 10:11 ` Peter Maydell
2021-08-18 19:19 ` [PATCH v3 62/66] tcg/s390: " Richard Henderson
2021-08-20 10:12 ` Peter Maydell
2021-08-18 19:19 ` [PATCH v3 63/66] tcg/tci: " Richard Henderson
2021-08-20 10:14 ` Peter Maydell
2021-08-22 7:59 ` Richard Henderson
2021-08-22 12:32 ` Peter Maydell
2021-08-22 17:09 ` Richard Henderson
2021-08-18 19:19 ` [PATCH v3 64/66] tcg: Canonicalize alignment flags in MemOp Richard Henderson
2021-08-18 21:24 ` Philippe Mathieu-Daudé
2021-08-18 19:19 ` [PATCH v3 65/66] tcg/riscv: Support raising sigbus for user-only Richard Henderson
2021-08-18 19:19 ` [PATCH v3 66/66] tcg/riscv: Remove add with zero on user-only memory access Richard Henderson
2021-08-30 21:29 ` Philippe Mathieu-Daudé
2021-08-30 22:38 ` Alistair Francis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210818191920.390759-60-richard.henderson@linaro.org \
--to=richard.henderson@linaro.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).