qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Richard Henderson <richard.henderson@linaro.org>
To: qemu-devel@nongnu.org
Cc: peter.maydell@linaro.org, Ilya Leoshkevich <iii@linux.ibm.com>
Subject: [PULL 02/44] accel/tcg: Clear PAGE_WRITE before translation
Date: Mon, 13 Sep 2021 17:14:14 -0700	[thread overview]
Message-ID: <20210914001456.793490-3-richard.henderson@linaro.org> (raw)
In-Reply-To: <20210914001456.793490-1-richard.henderson@linaro.org>

From: Ilya Leoshkevich <iii@linux.ibm.com>

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>
---
 include/exec/translate-all.h |  1 +
 include/exec/translator.h    | 39 ++++++++++++++----------
 accel/tcg/translate-all.c    | 59 +++++++++++++++++++++---------------
 accel/tcg/translator.c       | 39 ++++++++++++++++++++++++
 4 files changed, 97 insertions(+), 41 deletions(-)

diff --git a/include/exec/translate-all.h b/include/exec/translate-all.h
index a557b4e2bb..9f646389af 100644
--- a/include/exec/translate-all.h
+++ b/include/exec/translate-all.h
@@ -33,6 +33,7 @@ void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end);
 void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr);
 
 #ifdef CONFIG_USER_ONLY
+void page_protect(tb_page_addr_t page_addr);
 int page_unprotect(target_ulong address, uintptr_t pc);
 #endif
 
diff --git a/include/exec/translator.h b/include/exec/translator.h
index 6c054e8d05..9bc46eda59 100644
--- a/include/exec/translator.h
+++ b/include/exec/translator.h
@@ -23,6 +23,7 @@
 #include "exec/exec-all.h"
 #include "exec/cpu_ldst.h"
 #include "exec/plugin-gen.h"
+#include "exec/translate-all.h"
 #include "tcg/tcg.h"
 
 
@@ -74,6 +75,17 @@ typedef struct DisasContextBase {
     int num_insns;
     int max_insns;
     bool singlestep_enabled;
+#ifdef CONFIG_USER_ONLY
+    /*
+     * Guest address of the last byte of the last protected page.
+     *
+     * Pages containing the translated instructions are made non-writable in
+     * order to achieve consistency in case another thread is modifying the
+     * code while translate_insn() fetches the instruction bytes piecemeal.
+     * Such writer threads are blocked on mmap_lock() in page_unprotect().
+     */
+    target_ulong page_protect_end;
+#endif
 } DisasContextBase;
 
 /**
@@ -156,28 +168,23 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest);
  */
 
 #define GEN_TRANSLATOR_LD(fullname, type, load_fn, swap_fn)             \
-    static inline type                                                  \
-    fullname ## _swap(CPUArchState *env, DisasContextBase *dcbase,      \
-                      abi_ptr pc, bool do_swap)                         \
-    {                                                                   \
-        type ret = load_fn(env, pc);                                    \
-        if (do_swap) {                                                  \
-            ret = swap_fn(ret);                                         \
-        }                                                               \
-        plugin_insn_append(&ret, sizeof(ret));                          \
-        return ret;                                                     \
-    }                                                                   \
+    type fullname ## _swap(CPUArchState *env, DisasContextBase *dcbase, \
+                           abi_ptr pc, bool do_swap);                   \
     static inline type fullname(CPUArchState *env,                      \
                                 DisasContextBase *dcbase, abi_ptr pc)   \
     {                                                                   \
         return fullname ## _swap(env, dcbase, pc, false);               \
     }
 
-GEN_TRANSLATOR_LD(translator_ldub, uint8_t, cpu_ldub_code, /* no swap */)
-GEN_TRANSLATOR_LD(translator_ldsw, int16_t, cpu_ldsw_code, bswap16)
-GEN_TRANSLATOR_LD(translator_lduw, uint16_t, cpu_lduw_code, bswap16)
-GEN_TRANSLATOR_LD(translator_ldl, uint32_t, cpu_ldl_code, bswap32)
-GEN_TRANSLATOR_LD(translator_ldq, uint64_t, cpu_ldq_code, bswap64)
+#define FOR_EACH_TRANSLATOR_LD(F)                                       \
+    F(translator_ldub, uint8_t, cpu_ldub_code, /* no swap */)           \
+    F(translator_ldsw, int16_t, cpu_ldsw_code, bswap16)                 \
+    F(translator_lduw, uint16_t, cpu_lduw_code, bswap16)                \
+    F(translator_ldl, uint32_t, cpu_ldl_code, bswap32)                  \
+    F(translator_ldq, uint64_t, cpu_ldq_code, bswap64)
+
+FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD)
+
 #undef GEN_TRANSLATOR_LD
 
 #endif  /* EXEC__TRANSLATOR_H */
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index bbfcfb698c..fb9ebfad9e 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -1297,31 +1297,8 @@ static inline void tb_page_add(PageDesc *p, TranslationBlock *tb,
     invalidate_page_bitmap(p);
 
 #if defined(CONFIG_USER_ONLY)
-    if (p->flags & PAGE_WRITE) {
-        target_ulong addr;
-        PageDesc *p2;
-        int prot;
-
-        /* force the host page as non writable (writes will have a
-           page fault + mprotect overhead) */
-        page_addr &= qemu_host_page_mask;
-        prot = 0;
-        for (addr = page_addr; addr < page_addr + qemu_host_page_size;
-            addr += TARGET_PAGE_SIZE) {
-
-            p2 = page_find(addr >> TARGET_PAGE_BITS);
-            if (!p2) {
-                continue;
-            }
-            prot |= p2->flags;
-            p2->flags &= ~PAGE_WRITE;
-          }
-        mprotect(g2h_untagged(page_addr), qemu_host_page_size,
-                 (prot & PAGE_BITS) & ~PAGE_WRITE);
-        if (DEBUG_TB_INVALIDATE_GATE) {
-            printf("protecting code page: 0x" TB_PAGE_ADDR_FMT "\n", page_addr);
-        }
-    }
+    /* translator_loop() must have made all TB pages non-writable */
+    assert(!(p->flags & PAGE_WRITE));
 #else
     /* if some code is already present, then the pages are already
        protected. So we handle the case where only the first TB is
@@ -2394,6 +2371,38 @@ int page_check_range(target_ulong start, target_ulong len, int flags)
     return 0;
 }
 
+void page_protect(tb_page_addr_t page_addr)
+{
+    target_ulong addr;
+    PageDesc *p;
+    int prot;
+
+    p = page_find(page_addr >> TARGET_PAGE_BITS);
+    if (p && (p->flags & PAGE_WRITE)) {
+        /*
+         * Force the host page as non writable (writes will have a page fault +
+         * mprotect overhead).
+         */
+        page_addr &= qemu_host_page_mask;
+        prot = 0;
+        for (addr = page_addr; addr < page_addr + qemu_host_page_size;
+             addr += TARGET_PAGE_SIZE) {
+
+            p = page_find(addr >> TARGET_PAGE_BITS);
+            if (!p) {
+                continue;
+            }
+            prot |= p->flags;
+            p->flags &= ~PAGE_WRITE;
+        }
+        mprotect(g2h_untagged(page_addr), qemu_host_page_size,
+                 (prot & PAGE_BITS) & ~PAGE_WRITE);
+        if (DEBUG_TB_INVALIDATE_GATE) {
+            printf("protecting code page: 0x" TB_PAGE_ADDR_FMT "\n", page_addr);
+        }
+    }
+}
+
 /* called from signal handler: invalidate the code and unprotect the
  * page. Return 0 if the fault was not handled, 1 if it was handled,
  * and 2 if it was handled but the caller must cause the TB to be
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
-- 
2.25.1



  parent reply	other threads:[~2021-09-14  0:17 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-09-14  0:14 [PULL 00/44] tcg patch queue, v2 Richard Henderson
2021-09-14  0:14 ` [PULL 01/44] accel/tcg: Add DisasContextBase argument to translator_ld* Richard Henderson
2021-09-14  0:14 ` Richard Henderson [this message]
2021-09-14  0:14 ` [PULL 03/44] tcg/i386: Split P_VEXW from P_REXW Richard Henderson
2021-09-14  0:14 ` [PULL 04/44] accel/tcg: remove redundant TCG_KICK_PERIOD define Richard Henderson
2021-09-14  0:14 ` [PULL 05/44] tcg: Remove tcg_global_reg_new defines Richard Henderson
2021-09-14  0:14 ` [PULL 06/44] tcg/ppc: Replace TCG_TARGET_CALL_DARWIN with _CALL_DARWIN Richard Henderson
2021-09-14  0:14 ` [PULL 07/44] tcg/ppc: Ensure _CALL_SYSV is set for 32-bit ELF Richard Henderson
2021-09-14  0:14 ` [PULL 08/44] tcg/arm: Fix tcg_out_vec_op function signature Richard Henderson
2021-09-14  0:14 ` [PULL 09/44] target/avr: Remove pointless use of CONFIG_USER_ONLY definition Richard Henderson
2021-09-14  0:14 ` [PULL 10/44] target/i386: Restrict sysemu-only fpu_helper helpers Richard Henderson
2021-09-14  0:14 ` [PULL 11/44] target/i386: Simplify TARGET_X86_64 #ifdef'ry Richard Henderson
2021-09-14  0:14 ` [PULL 12/44] target/xtensa: Restrict do_transaction_failed() to sysemu Richard Henderson
2021-09-14  0:14 ` [PULL 13/44] accel/tcg: Rename user-mode do_interrupt hack as fake_user_interrupt Richard Henderson
2021-09-14  0:14 ` [PULL 14/44] target/alpha: Restrict cpu_exec_interrupt() handler to sysemu Richard Henderson
2021-09-14  0:14 ` [PULL 15/44] target/arm: " Richard Henderson
2021-09-14  0:14 ` [PULL 16/44] target/cris: " Richard Henderson
2021-09-14  0:14 ` [PULL 17/44] target/hppa: " Richard Henderson
2021-09-14  0:14 ` [PULL 18/44] target/i386: " Richard Henderson
2021-09-14  0:14 ` [PULL 19/44] target/i386: Move x86_cpu_exec_interrupt() under sysemu/ folder Richard Henderson
2021-09-14  0:14 ` [PULL 20/44] target/m68k: Restrict cpu_exec_interrupt() handler to sysemu Richard Henderson
2021-09-14  0:14 ` [PULL 21/44] target/microblaze: " Richard Henderson
2021-09-14  0:14 ` [PULL 22/44] target/mips: " Richard Henderson
2021-09-14  0:14 ` [PULL 23/44] target/nios2: " Richard Henderson
2021-09-14  0:14 ` [PULL 24/44] target/openrisc: " Richard Henderson
2021-09-14  0:14 ` [PULL 25/44] target/ppc: " Richard Henderson
2021-09-14  0:14 ` [PULL 26/44] target/riscv: " Richard Henderson
2021-09-14  0:14 ` [PULL 27/44] target/sh4: " Richard Henderson
2021-09-14  0:14 ` [PULL 28/44] target/sparc: " Richard Henderson
2021-09-14  0:14 ` [PULL 29/44] target/rx: " Richard Henderson
2021-09-14  0:14 ` [PULL 30/44] target/xtensa: " Richard Henderson
2021-09-14  0:14 ` [PULL 31/44] accel/tcg: Restrict TCGCPUOps::cpu_exec_interrupt() " Richard Henderson
2021-09-14  0:14 ` [PULL 32/44] user: Remove cpu_get_pic_interrupt() stubs Richard Henderson
2021-09-14  0:14 ` [PULL 33/44] user: Mark cpu_loop() with noreturn attribute Richard Henderson
2021-09-14  0:14 ` [PULL 34/44] accel/tcg/user-exec: Fix read-modify-write of code on s390 hosts Richard Henderson
2021-09-14  0:14 ` [PULL 35/44] tcg/arm: Remove fallback definition of __ARM_ARCH Richard Henderson
2021-09-14  5:58   ` Philippe Mathieu-Daudé
2021-09-14  0:14 ` [PULL 36/44] tcg/arm: Standardize on tcg_out_<branch>_{reg,imm} Richard Henderson
2021-09-14  0:14 ` [PULL 37/44] tcg/arm: Simplify use_armv5t_instructions Richard Henderson
2021-09-14  0:14 ` [PULL 38/44] tcg/arm: Support armv4t in tcg_out_goto and tcg_out_call Richard Henderson
2021-09-14  0:14 ` [PULL 39/44] tcg/arm: Split out tcg_out_ldstm Richard Henderson
2021-09-14  0:14 ` [PULL 40/44] tcg/arm: Simplify usage of encode_imm Richard Henderson
2021-09-14  0:14 ` [PULL 41/44] tcg/arm: Drop inline markers Richard Henderson
2021-09-14  0:14 ` [PULL 42/44] tcg/arm: Give enum arm_cond_code_e a typedef and use it Richard Henderson
2021-09-14  0:14 ` [PULL 43/44] tcg/arm: More use of the ARMInsn enum Richard Henderson
2021-09-14  0:14 ` [PULL 44/44] tcg/arm: More use of the TCGReg enum Richard Henderson
2021-09-14 12:39 ` [PULL 00/44] tcg patch queue, v2 Peter Maydell

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=20210914001456.793490-3-richard.henderson@linaro.org \
    --to=richard.henderson@linaro.org \
    --cc=iii@linux.ibm.com \
    --cc=peter.maydell@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).