user-level: 0.869 mistranslation: 0.853 permissions: 0.839 semantic: 0.797 register: 0.766 risc-v: 0.766 graphic: 0.764 architecture: 0.733 performance: 0.728 peripherals: 0.717 ppc: 0.716 TCG: 0.713 assembly: 0.709 virtual: 0.702 hypervisor: 0.700 device: 0.696 vnc: 0.668 debug: 0.659 arm: 0.649 PID: 0.646 files: 0.606 VMM: 0.597 x86: 0.589 KVM: 0.586 boot: 0.583 kernel: 0.550 network: 0.527 socket: 0.523 i386: 0.504 -------------------- TCG: 0.963 kernel: 0.625 assembly: 0.167 virtual: 0.108 hypervisor: 0.084 x86: 0.077 VMM: 0.058 PID: 0.055 KVM: 0.049 files: 0.048 debug: 0.047 ppc: 0.038 user-level: 0.037 risc-v: 0.037 vnc: 0.033 device: 0.031 register: 0.030 i386: 0.029 socket: 0.027 permissions: 0.025 semantic: 0.015 architecture: 0.014 arm: 0.013 network: 0.012 peripherals: 0.010 performance: 0.008 boot: 0.006 graphic: 0.004 mistranslation: 0.002 Use-after-free after flush in TCG accelerator I believe I found a UAF in TCG that can lead to a guest VM escape. The security list informed me "This can not be treated as a security issue." and to post it here. I am looking at the 4.2.0 source code. The issue requires a race and I will try to describe it in terms of three concurrent threads. I am looking at the 4.2.0 source code. The issue requires a race and I will try to describe it in terms of three concurrent threads. Thread A: A1. qemu_tcg_cpu_thread_fn runs work loop A2. qemu_wait_io_event => qemu_wait_io_event_common => process_queued_cpu_work A3. start_exclusive critical section entered A4. do_tb_flush is called, TB memory freed/re-allocated A5. end_exclusive exits critical section Thread B: B1. qemu_tcg_cpu_thread_fn runs work loop B2. tcg_cpu_exec => cpu_exec => tb_find => tb_gen_code B3. tcg_tb_alloc obtains a new TB Thread C: C1. qemu_tcg_cpu_thread_fn runs work loop C2. cpu_exec_step_atomic executes C3. TB obtained with tb_lookup__cpu_state or tb_gen_code C4. start_exclusive critical section entered C5. cpu_tb_exec executes the TB code C6. end_exclusive exits critical section Consider the following sequence of events: B2 => B3 => C3 (same TB as B2) => A3 => A4 (TB freed) => A5 => B2 => B3 (re-allocates TB from B2) => C4 => C5 (freed/reused TB now executing) => C6 In short, because thread C uses the TB in the critical section, there is no guarantee that the pointer has not been "freed" (rather the memory is marked as re-usable) and therefore a use-after-free occurs. Since the TCG generated code can be in the same memory as the TB data structure, it is possible for an attacker to overwrite the UAF pointer with code generated from TCG. This can overwrite key pointer values and could lead to code execution on the host outside of the TCG sandbox. 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. Signed-off-by: Alex Bennée