qemu/accel/tcg
Peter Maydell 9c4bbee9e3 page_unprotect(): handle calls to pages that are PAGE_WRITE
If multiple guest threads in user-mode emulation write to a
page which QEMU has marked read-only because of cached TCG
translations, the threads can race in page_unprotect:

 * threads A & B both try to do a write to a page with code in it at
   the same time (ie which we've made non-writeable, so SEGV)
 * they race into the signal handler with this faulting address
 * thread A happens to get to page_unprotect() first and takes the
   mmap lock, so thread B sits waiting for it to be done
 * A then finds the page, marks it PAGE_WRITE and mprotect()s it writable
 * A can then continue OK (returns from signal handler to retry the
   memory access)
 * ...but when B gets the mmap lock it finds that the page is already
   PAGE_WRITE, and so it exits page_unprotect() via the "not due to
   protected translation" code path, and wrongly delivers the signal
   to the guest rather than just retrying the access

In particular, this meant that trying to run 'javac' in user-mode
emulation would fail with a spurious guest SIGSEGV.

Handle this by making page_unprotect() assume that a call for a page
which is already PAGE_WRITE is due to a race of this sort and return
a "fault handled" indication.

Since this would cause an infinite loop if we ever called
page_unprotect() for some other kind of fault than "write failed due
to bad access permissions", tighten the condition in
handle_cpu_signal() to check the signal number and si_code, and add a
comment so that if somebody does ever find themselves debugging an
infinite loop of faults they have some clue about why.

(The trick for identifying the correct setting for
current_tb_invalidated for thread B (needed to handle the precise-SMC
case) is due to Richard Henderson.  Paolo Bonzini suggested just
relying on si_code rather than trying anything more complicated.)

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-Id: <1511879725-9576-3-git-send-email-peter.maydell@linaro.org>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
2018-01-23 14:20:53 +01:00
..
atomic_template.h accel/tcg: Handle atomic accesses to notdirty memory correctly 2017-11-21 12:09:25 +00:00
cpu-exec-common.c accel/tcg/cpu-exec-common.c: Remove unnecessary include of memory-internal.h 2017-12-18 17:07:02 +03:00
cpu-exec.c tcg: add cs_base and flags to -d exec output 2017-12-29 12:43:40 -08:00
cputlb.c accel/tcg: Handle atomic accesses to notdirty memory correctly 2017-11-21 12:09:25 +00:00
Makefile.objs accel/tcg: move tcg-runtime to accel/tcg/ 2017-09-17 06:52:19 -07:00
softmmu_template.h accel/tcg: allow to invalidate a write TLB entry immediately 2017-10-20 13:32:10 +02:00
tcg-all.c tcg: make tcg_allowed global 2017-07-04 16:01:16 +02:00
tcg-runtime.c tcg: add cs_base and flags to -d exec output 2017-12-29 12:43:40 -08:00
tcg-runtime.h tcg: remove addr argument from lookup_tb_ptr 2017-10-10 07:37:10 -07:00
trace-events trace-events: fix code style: print 0x before hex numbers 2017-08-01 12:13:07 +01:00
translate-all.c page_unprotect(): handle calls to pages that are PAGE_WRITE 2018-01-23 14:20:53 +01:00
translate-all.h tcg: move tcg backend files into accel/tcg/ 2017-06-15 11:04:06 +02:00
translator.c tcg: convert tb->cflags reads to tb_cflags(tb) 2017-10-24 13:53:41 -07:00
user-exec-stub.c accel/tcg: move user-exec to accel/tcg/ 2017-09-17 06:52:19 -07:00
user-exec.c page_unprotect(): handle calls to pages that are PAGE_WRITE 2018-01-23 14:20:53 +01:00