diff options
author | Ilya Leoshkevich <iii@linux.ibm.com> | 2021-08-05 22:48:35 +0200 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2021-09-14 12:00:20 -0700 |
commit | f025692c992c1ed6cc54ac2802cff14e9052c0d3 (patch) | |
tree | 01931a3394d5f38e9f237de94ac0b82fcce8ff22 /accel/tcg/translator.c | |
parent | 4e116893c6079b51efdc9e226be3f1a530f47f5e (diff) |
accel/tcg: Clear PAGE_WRITE before translation
translate_insn() implementations fetch instruction bytes piecemeal,
which can cause qemu-user to generate inconsistent translations if
another thread modifies them concurrently [1].
Fix by making pages containing translated instruction non-writable
right before loading instruction bytes from them.
[1] https://lists.nongnu.org/archive/html/qemu-devel/2021-08/msg00644.html
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Message-Id: <20210805204835.158918-1-iii@linux.ibm.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'accel/tcg/translator.c')
-rw-r--r-- | accel/tcg/translator.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index c53a7f8e44..390bd9db0a 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -42,6 +42,15 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest) return ((db->pc_first ^ dest) & TARGET_PAGE_MASK) == 0; } +static inline void translator_page_protect(DisasContextBase *dcbase, + target_ulong pc) +{ +#ifdef CONFIG_USER_ONLY + dcbase->page_protect_end = pc | ~TARGET_PAGE_MASK; + page_protect(pc); +#endif +} + void translator_loop(const TranslatorOps *ops, DisasContextBase *db, CPUState *cpu, TranslationBlock *tb, int max_insns) { @@ -56,6 +65,7 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db, db->num_insns = 0; db->max_insns = max_insns; db->singlestep_enabled = cflags & CF_SINGLE_STEP; + translator_page_protect(db, db->pc_next); ops->init_disas_context(db, cpu); tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ @@ -137,3 +147,32 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db, } #endif } + +static inline void translator_maybe_page_protect(DisasContextBase *dcbase, + target_ulong pc, size_t len) +{ +#ifdef CONFIG_USER_ONLY + target_ulong end = pc + len - 1; + + if (end > dcbase->page_protect_end) { + translator_page_protect(dcbase, end); + } +#endif +} + +#define GEN_TRANSLATOR_LD(fullname, type, load_fn, swap_fn) \ + type fullname ## _swap(CPUArchState *env, DisasContextBase *dcbase, \ + abi_ptr pc, bool do_swap) \ + { \ + translator_maybe_page_protect(dcbase, pc, sizeof(type)); \ + type ret = load_fn(env, pc); \ + if (do_swap) { \ + ret = swap_fn(ret); \ + } \ + plugin_insn_append(&ret, sizeof(ret)); \ + return ret; \ + } + +FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD) + +#undef GEN_TRANSLATOR_LD |