Skip to content

Commit e735a5d

Browse files
committed
KVM: arm64: Don't retire aborted MMIO instruction
Returning an abort to the guest for an unsupported MMIO access is a documented feature of the KVM UAPI. Nevertheless, it's clear that this plumbing has seen limited testing, since userspace can trivially cause a WARN in the MMIO return: WARNING: CPU: 0 PID: 30558 at arch/arm64/include/asm/kvm_emulate.h:536 kvm_handle_mmio_return+0x46c/0x5c4 arch/arm64/include/asm/kvm_emulate.h:536 Call trace: kvm_handle_mmio_return+0x46c/0x5c4 arch/arm64/include/asm/kvm_emulate.h:536 kvm_arch_vcpu_ioctl_run+0x98/0x15b4 arch/arm64/kvm/arm.c:1133 kvm_vcpu_ioctl+0x75c/0xa78 virt/kvm/kvm_main.c:4487 __do_sys_ioctl fs/ioctl.c:51 [inline] __se_sys_ioctl fs/ioctl.c:893 [inline] __arm64_sys_ioctl+0x14c/0x1c8 fs/ioctl.c:893 __invoke_syscall arch/arm64/kernel/syscall.c:35 [inline] invoke_syscall+0x98/0x2b8 arch/arm64/kernel/syscall.c:49 el0_svc_common+0x1e0/0x23c arch/arm64/kernel/syscall.c:132 do_el0_svc+0x48/0x58 arch/arm64/kernel/syscall.c:151 el0_svc+0x38/0x68 arch/arm64/kernel/entry-common.c:712 el0t_64_sync_handler+0x90/0xfc arch/arm64/kernel/entry-common.c:730 el0t_64_sync+0x190/0x194 arch/arm64/kernel/entry.S:598 The splat is complaining that KVM is advancing PC while an exception is pending, i.e. that KVM is retiring the MMIO instruction despite a pending synchronous external abort. Womp womp. Fix the glaring UAPI bug by skipping over all the MMIO emulation in case there is a pending synchronous exception. Note that while userspace is capable of pending an asynchronous exception (SError, IRQ, or FIQ), it is still safe to retire the MMIO instruction in this case as (1) they are by definition asynchronous, and (2) KVM relies on hardware support for pending/delivering these exceptions instead of the software state machine for advancing PC. Cc: stable@vger.kernel.org Fixes: da34517 ("KVM: arm/arm64: Allow user injection of external data aborts") Reported-by: Alexander Potapenko <glider@google.com> Reviewed-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20241025203106.3529261-2-oliver.upton@linux.dev Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent 8e929cb commit e735a5d

File tree

1 file changed

+30
-2
lines changed

1 file changed

+30
-2
lines changed

arch/arm64/kvm/mmio.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,31 @@ unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len)
7272
return data;
7373
}
7474

75+
static bool kvm_pending_sync_exception(struct kvm_vcpu *vcpu)
76+
{
77+
if (!vcpu_get_flag(vcpu, PENDING_EXCEPTION))
78+
return false;
79+
80+
if (vcpu_el1_is_32bit(vcpu)) {
81+
switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) {
82+
case unpack_vcpu_flag(EXCEPT_AA32_UND):
83+
case unpack_vcpu_flag(EXCEPT_AA32_IABT):
84+
case unpack_vcpu_flag(EXCEPT_AA32_DABT):
85+
return true;
86+
default:
87+
return false;
88+
}
89+
} else {
90+
switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) {
91+
case unpack_vcpu_flag(EXCEPT_AA64_EL1_SYNC):
92+
case unpack_vcpu_flag(EXCEPT_AA64_EL2_SYNC):
93+
return true;
94+
default:
95+
return false;
96+
}
97+
}
98+
}
99+
75100
/**
76101
* kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
77102
* or in-kernel IO emulation
@@ -84,8 +109,11 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu)
84109
unsigned int len;
85110
int mask;
86111

87-
/* Detect an already handled MMIO return */
88-
if (unlikely(!vcpu->mmio_needed))
112+
/*
113+
* Detect if the MMIO return was already handled or if userspace aborted
114+
* the MMIO access.
115+
*/
116+
if (unlikely(!vcpu->mmio_needed || kvm_pending_sync_exception(vcpu)))
89117
return 1;
90118

91119
vcpu->mmio_needed = 0;

0 commit comments

Comments
 (0)