target/i386: allow transition to virtual-8086 mode only if CPL == 0 and CPU is not in long mode
According to the pseudocode for the IRET instruction in both the Intel 64 and IA-32 Architectures Software Developer's Manual and the AMD64 Architecture Programmer's Manual, a transition to virtual-8086 mode is allowed only if all of the following conditions are met: 1. The new EFLAGS.VM bit is set to 1. 2. The Current Privilege Level (CPL) is 0. 3. The CPU is in protected mode (and not in long mode). Currently, QEMU performs only the first check. This omission allows a transition to virtual-8086 mode from long mode, and also enables the guest's userspace to trigger this switch. During a legitimate transition, the EFLAGS register is updated in a way that allows modification of sensitive fields, such as IOPL and IF (which is expected, as only privileged code should be able to initiate this transition). However, due to the lack of appropriate checks, an unprivileged guest userspace process can now force this transition and freely modify these fields. This allows the userspace to: 1. Disable interrupts, preventing other processes from running on the CPU. 2. Gain direct hardware I/O access by elevating EFLAGS.IOPL to 3. 3. Crash the guest kernel by setting CS and SS to resemble segments with RPL = 0 and triggering an exception. Since the kernel is unaware that the process entered virtual-8086 mode, it will misinterpret the exception as originating from kernel space. This patch fixes this bug by adding the missing CPL and long mode checks before jumping to the `return_to_vm86` label. Fixes: 90a9fdae1f1a ("more ring 0 operations") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3583 Signed-off-by: Andrey Polivoda <apolivodaa433@gmail.com> Cc: qemu-devel@nongnu.org Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Richard Henderson <richard.henderson@linaro.org> Link: https://lore.kernel.org/r/20260622082119.11903-1-apolivodaa433@gmail.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>