qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

accel/tcg: fix race in cpu_exec_step_atomic (bug 1863025)

The bug describes a race whereby cpu_exec_step_atomic can acquire a TB
which is invalidated by a tb_flush before we execute it. This doesn't
affect the other cpu_exec modes as a tb_flush by it's nature can only
occur on a quiescent system. The race was described as:

B2. tcg_cpu_exec => cpu_exec => tb_find => tb_gen_code
B3. tcg_tb_alloc obtains a new TB

C3. TB obtained with tb_lookup__cpu_state or tb_gen_code
(same TB as B2)

A3. start_exclusive critical section entered
A4. do_tb_flush is called, TB memory freed/re-allocated
A5. end_exclusive exits critical section

B2. tcg_cpu_exec => cpu_exec => tb_find => tb_gen_code
B3. tcg_tb_alloc reallocates TB from B2

C4. start_exclusive critical section entered
C5. cpu_tb_exec executes the TB code that was free in A4

The simplest fix is to widen the exclusive period to include the TB
lookup. As a result we can drop the complication of checking we are in
the exclusive region before we end it.

Cc: Yifan <me@yifanlu.com>
Buglink: https://bugs.launchpad.net/qemu/+bug/1863025
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20200214144952.15502-1-alex.bennee@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

authored by

Alex Bennée and committed by
Richard Henderson
886cc689 e0175b71

+11 -10
+11 -10
accel/tcg/cpu-exec.c
··· 240 240 uint32_t cf_mask = cflags & CF_HASH_MASK; 241 241 242 242 if (sigsetjmp(cpu->jmp_env, 0) == 0) { 243 + start_exclusive(); 244 + 243 245 tb = tb_lookup__cpu_state(cpu, &pc, &cs_base, &flags, cf_mask); 244 246 if (tb == NULL) { 245 247 mmap_lock(); 246 248 tb = tb_gen_code(cpu, pc, cs_base, flags, cflags); 247 249 mmap_unlock(); 248 250 } 249 - 250 - start_exclusive(); 251 251 252 252 /* Since we got here, we know that parallel_cpus must be true. */ 253 253 parallel_cpus = false; ··· 271 271 qemu_plugin_disable_mem_helpers(cpu); 272 272 } 273 273 274 - if (cpu_in_exclusive_context(cpu)) { 275 - /* We might longjump out of either the codegen or the 276 - * execution, so must make sure we only end the exclusive 277 - * region if we started it. 278 - */ 279 - parallel_cpus = true; 280 - end_exclusive(); 281 - } 274 + 275 + /* 276 + * As we start the exclusive region before codegen we must still 277 + * be in the region if we longjump out of either the codegen or 278 + * the execution. 279 + */ 280 + g_assert(cpu_in_exclusive_context(cpu)); 281 + parallel_cpus = true; 282 + end_exclusive(); 282 283 } 283 284 284 285 struct tb_desc {