summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Polivoda <apolivodaa433@gmail.com>2026-06-22 18:21:19 +1000
committerMichael Tokarev <mjt@tls.msk.ru>2026-08-21 20:02:37 +0300
commit07e8f29d18e50dccf7376c6b601bc6f92f5de6f2 (patch)
treed49192751f684790a3e397dbda0c66f42efe10f4
parentb610e0ad00d8a7b34bee52e5b2ffabe154161f97 (diff)
downloadqemu-07e8f29d18e50dccf7376c6b601bc6f92f5de6f2.tar.gz
qemu-07e8f29d18e50dccf7376c6b601bc6f92f5de6f2.zip
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> (cherry picked from commit 36f634fe4ab6b266031164ab8d1160e6d11addda) Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
-rw-r--r--target/i386/tcg/seg_helper.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c
index 07ff1cb47e..8158d6175e 100644
--- a/target/i386/tcg/seg_helper.c
+++ b/target/i386/tcg/seg_helper.c
@@ -2046,7 +2046,8 @@ static inline void helper_ret_protected(CPUX86State *env, int shift,
new_cs = popl(&sa) & 0xffff;
if (is_iret) {
new_eflags = popl(&sa);
- if (new_eflags & VM_MASK) {
+ bool allow_vm86 = (cpl == 0) && !(env->hflags & HF_LMA_MASK);
+ if ((new_eflags & VM_MASK) && allow_vm86) {
goto return_to_vm86;
}
}