* [PATCH RFC 0/1] tcg: Always pass the full write size to notdirty_write() @ 2023-08-07 13:56 Ilya Leoshkevich 2023-08-07 13:56 ` [PATCH RFC 1/1] " Ilya Leoshkevich 0 siblings, 1 reply; 5+ messages in thread From: Ilya Leoshkevich @ 2023-08-07 13:56 UTC (permalink / raw) To: Richard Henderson, Paolo Bonzini Cc: qemu-devel, Peter Maydell, Ilya Leoshkevich Hi, this is the fix for an issue I complained about a few days back on the IRC. Unfortunately my reproducer [1] does not work anymore, so I'm sending this separately and as an RFC. The user-visible effect was that: - If a TB writes to itself; - The address of the write is before the TB start; - The newly written instruction causes an exception; - Then single-stepping the instruction that does a write gets you to an interrupt handler and not to the newly written "bad" instruction. You can still see that something is wrong with the softmmu reproducer in the debugger though. In helper_vstl(), probe_write_access() does not lead to cpu_loop_exit_noexc() - which I think it should, but cpu_stq_be_data_ra() still does, masking the issue. Best regards, Ilya [1] https://lists.gnu.org/archive/html/qemu-devel/2023-08/msg01081.html Ilya Leoshkevich (1): tcg: Always pass the full write size to notdirty_write() accel/tcg/cputlb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) -- 2.41.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH RFC 1/1] tcg: Always pass the full write size to notdirty_write() 2023-08-07 13:56 [PATCH RFC 0/1] tcg: Always pass the full write size to notdirty_write() Ilya Leoshkevich @ 2023-08-07 13:56 ` Ilya Leoshkevich 2023-08-07 18:21 ` Richard Henderson 0 siblings, 1 reply; 5+ messages in thread From: Ilya Leoshkevich @ 2023-08-07 13:56 UTC (permalink / raw) To: Richard Henderson, Paolo Bonzini Cc: qemu-devel, Peter Maydell, Ilya Leoshkevich One of notdirty_write()'s responsibilities is detecting self-modifying code. Some functions pass the full size of a write to it, some pass 1. When a write to a code section begins before a TB start, but then overlaps the TB, the paths that pass 1 don't flush a TB and don't return to the translator loop. This may be masked, one example being HELPER(vstl). There, probe_write_access() ultimately calls notdirty_write() with a size of 1 and misses self-modifying code. However, cpu_stq_be_data_ra() ultimately calls mmu_watch_or_dirty(), which in turn calls notdirty_write() with the full size. It's still worth improving this, because there may still be user-visible adverse effects in other helpers. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> --- accel/tcg/cputlb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index d68fa6867ce..aa3cffbc11a 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1582,7 +1582,7 @@ int probe_access_full(CPUArchState *env, vaddr addr, int size, /* Handle clean RAM pages. */ if (unlikely(flags & TLB_NOTDIRTY)) { - notdirty_write(env_cpu(env), addr, 1, *pfull, retaddr); + notdirty_write(env_cpu(env), addr, size, *pfull, retaddr); flags &= ~TLB_NOTDIRTY; } @@ -1605,7 +1605,7 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size, /* Handle clean RAM pages. */ if (unlikely(flags & TLB_NOTDIRTY)) { - notdirty_write(env_cpu(env), addr, 1, *pfull, 0); + notdirty_write(env_cpu(env), addr, size, *pfull, 0); flags &= ~TLB_NOTDIRTY; } @@ -1626,7 +1626,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size, /* Handle clean RAM pages. */ if (unlikely(flags & TLB_NOTDIRTY)) { - notdirty_write(env_cpu(env), addr, 1, full, retaddr); + notdirty_write(env_cpu(env), addr, size, full, retaddr); flags &= ~TLB_NOTDIRTY; } @@ -1661,7 +1661,7 @@ void *probe_access(CPUArchState *env, vaddr addr, int size, /* Handle clean RAM pages. */ if (flags & TLB_NOTDIRTY) { - notdirty_write(env_cpu(env), addr, 1, full, retaddr); + notdirty_write(env_cpu(env), addr, size, full, retaddr); } } -- 2.41.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH RFC 1/1] tcg: Always pass the full write size to notdirty_write() 2023-08-07 13:56 ` [PATCH RFC 1/1] " Ilya Leoshkevich @ 2023-08-07 18:21 ` Richard Henderson 2023-08-08 9:59 ` Ilya Leoshkevich 0 siblings, 1 reply; 5+ messages in thread From: Richard Henderson @ 2023-08-07 18:21 UTC (permalink / raw) To: Ilya Leoshkevich, Paolo Bonzini; +Cc: qemu-devel, Peter Maydell On 8/7/23 06:56, Ilya Leoshkevich wrote: > One of notdirty_write()'s responsibilities is detecting self-modifying > code. Some functions pass the full size of a write to it, some pass 1. > When a write to a code section begins before a TB start, but then > overlaps the TB, the paths that pass 1 don't flush a TB and don't > return to the translator loop. > > This may be masked, one example being HELPER(vstl). There, > probe_write_access() ultimately calls notdirty_write() with a size of > 1 and misses self-modifying code. However, cpu_stq_be_data_ra() > ultimately calls mmu_watch_or_dirty(), which in turn calls > notdirty_write() with the full size. > > It's still worth improving this, because there may still be > user-visible adverse effects in other helpers. > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> IIRC there are some uses of probe_access_* that set size == 0. Should we adjust addr+size to cover the whole page for that case? That seems to be the intent, anyway. r~ > --- > accel/tcg/cputlb.c | 8 ++++---- > 1 file changed, 4 insertions(+), 4 deletions(-) > > diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c > index d68fa6867ce..aa3cffbc11a 100644 > --- a/accel/tcg/cputlb.c > +++ b/accel/tcg/cputlb.c > @@ -1582,7 +1582,7 @@ int probe_access_full(CPUArchState *env, vaddr addr, int size, > > /* Handle clean RAM pages. */ > if (unlikely(flags & TLB_NOTDIRTY)) { > - notdirty_write(env_cpu(env), addr, 1, *pfull, retaddr); > + notdirty_write(env_cpu(env), addr, size, *pfull, retaddr); > flags &= ~TLB_NOTDIRTY; > } > > @@ -1605,7 +1605,7 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size, > > /* Handle clean RAM pages. */ > if (unlikely(flags & TLB_NOTDIRTY)) { > - notdirty_write(env_cpu(env), addr, 1, *pfull, 0); > + notdirty_write(env_cpu(env), addr, size, *pfull, 0); > flags &= ~TLB_NOTDIRTY; > } > > @@ -1626,7 +1626,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size, > > /* Handle clean RAM pages. */ > if (unlikely(flags & TLB_NOTDIRTY)) { > - notdirty_write(env_cpu(env), addr, 1, full, retaddr); > + notdirty_write(env_cpu(env), addr, size, full, retaddr); > flags &= ~TLB_NOTDIRTY; > } > > @@ -1661,7 +1661,7 @@ void *probe_access(CPUArchState *env, vaddr addr, int size, > > /* Handle clean RAM pages. */ > if (flags & TLB_NOTDIRTY) { > - notdirty_write(env_cpu(env), addr, 1, full, retaddr); > + notdirty_write(env_cpu(env), addr, size, full, retaddr); > } > } > ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH RFC 1/1] tcg: Always pass the full write size to notdirty_write() 2023-08-07 18:21 ` Richard Henderson @ 2023-08-08 9:59 ` Ilya Leoshkevich 2023-08-08 14:23 ` Richard Henderson 0 siblings, 1 reply; 5+ messages in thread From: Ilya Leoshkevich @ 2023-08-08 9:59 UTC (permalink / raw) To: Richard Henderson, Paolo Bonzini; +Cc: qemu-devel, Peter Maydell On Mon, 2023-08-07 at 11:21 -0700, Richard Henderson wrote: > On 8/7/23 06:56, Ilya Leoshkevich wrote: > > One of notdirty_write()'s responsibilities is detecting self- > > modifying > > code. Some functions pass the full size of a write to it, some pass > > 1. > > When a write to a code section begins before a TB start, but then > > overlaps the TB, the paths that pass 1 don't flush a TB and don't > > return to the translator loop. > > > > This may be masked, one example being HELPER(vstl). There, > > probe_write_access() ultimately calls notdirty_write() with a size > > of > > 1 and misses self-modifying code. However, cpu_stq_be_data_ra() > > ultimately calls mmu_watch_or_dirty(), which in turn calls > > notdirty_write() with the full size. > > > > It's still worth improving this, because there may still be > > user-visible adverse effects in other helpers. > > > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > > IIRC there are some uses of probe_access_* that set size == 0. > Should we adjust addr+size to cover the whole page for that case? > That seems to be the intent, anyway. There is a comment that says we shouldn't do watchpoint/smc detection in this case: /* Per the interface, size == 0 merely faults the access. */ if (size == 0) { return NULL; } Come to think of it, qemu-user works this way too: SMC is detected on the actual access, not the probe: helper_vstl() cpu_stq_be_data_ra() ... stq_he_p() <signal handler called> host_signal_handler() handle_sigsegv_accerr_write() page_unprotect() tb_invalidate_phys_page_unwind() cpu_loop_exit_noexc() So all this is probably fine, I now think it's better to leave the code as is, especially given that I cannot reproduce the original problem anymore. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH RFC 1/1] tcg: Always pass the full write size to notdirty_write() 2023-08-08 9:59 ` Ilya Leoshkevich @ 2023-08-08 14:23 ` Richard Henderson 0 siblings, 0 replies; 5+ messages in thread From: Richard Henderson @ 2023-08-08 14:23 UTC (permalink / raw) To: Ilya Leoshkevich, Paolo Bonzini; +Cc: qemu-devel, Peter Maydell On 8/8/23 02:59, Ilya Leoshkevich wrote: > On Mon, 2023-08-07 at 11:21 -0700, Richard Henderson wrote: >> IIRC there are some uses of probe_access_* that set size == 0. >> Should we adjust addr+size to cover the whole page for that case? >> That seems to be the intent, anyway. > > There is a comment that says we shouldn't do watchpoint/smc detection > in this case: > > /* Per the interface, size == 0 merely faults the access. */ > if (size == 0) { > return NULL; > } > > Come to think of it, qemu-user works this way too: SMC is detected on > the actual access, not the probe: > > helper_vstl() > cpu_stq_be_data_ra() > ... > stq_he_p() > <signal handler called> > host_signal_handler() > handle_sigsegv_accerr_write() > page_unprotect() > tb_invalidate_phys_page_unwind() > cpu_loop_exit_noexc() > > So all this is probably fine, I now think it's better to leave the code > as is, especially given that I cannot reproduce the original problem > anymore. Ok then. r~ ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2023-08-08 14:23 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-08-07 13:56 [PATCH RFC 0/1] tcg: Always pass the full write size to notdirty_write() Ilya Leoshkevich 2023-08-07 13:56 ` [PATCH RFC 1/1] " Ilya Leoshkevich 2023-08-07 18:21 ` Richard Henderson 2023-08-08 9:59 ` Ilya Leoshkevich 2023-08-08 14:23 ` Richard Henderson
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).