From 36fa628605eca4642fa0c5eba93178a8725bb1df Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Mon, 25 Mar 2024 22:23:19 +0200 Subject: [PATCH] [NTOS:KE/x64] Loop in KiInitiateUserApc This is required since while interrupts are enabled, another user APC could get queued and we want to guarantee that those are all delivered before returning to user mode. --- ntoskrnl/ke/amd64/trap.S | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/ntoskrnl/ke/amd64/trap.S b/ntoskrnl/ke/amd64/trap.S index 93dce4215dc..30168f46549 100644 --- a/ntoskrnl/ke/amd64/trap.S +++ b/ntoskrnl/ke/amd64/trap.S @@ -416,7 +416,7 @@ FUNC KiPageFault /* Save page fault address */ mov rdx, cr2 mov [rbp + KTRAP_FRAME_FaultAddress], rdx - + /* If interrupts are off, do not enable them */ test dword ptr [rbp + KTRAP_FRAME_EFlags], EFLAGS_IF_MASK jz IntsDisabled @@ -1150,21 +1150,27 @@ PUBLIC KiInitiateUserApc mov rax, APC_LEVEL mov cr8, rax + /* Get the current thread */ + mov rbp, gs:[PcCurrentThread] + +deliver_apcs: + /* Enable interrupts */ sti - /* Get the current trap frame */ - mov rax, gs:[PcCurrentThread] - mov r8, [rax + KTHREAD_TrapFrame] - /* Call the C function */ mov ecx, 1 mov rdx, rsp + mov r8, [rbp + ThTrapFrame] call KiDeliverApc /* Disable interrupts again */ cli + /* Check if there are more APCs to deliver */ + cmp byte ptr [rbp + ThApcState + AsUserApcPending], 0 + jne deliver_apcs + /* Go back to PASSIVE_LEVEL */ mov rax, PASSIVE_LEVEL mov cr8, rax