[NTOS:KE/x64] Fix user APC delivery on syscall exit

We need to save the missing registers in the trap frame before calling KiInitiateUserApc, because they will be used to create the CONTEXT that is saved on the user mode stack, where KiUserApcDispatcher returns back to using NtContinue. This fixes remaining failures in kernel32_apitest QueueUserAPC.
This commit is contained in:
Timo Kreuzer 2024-04-02 22:55:54 +03:00
parent c4498d751d
commit 7589238b68

View file

@ -852,8 +852,34 @@ GLOBAL_LABEL KiSystemServiceExit
/* Check for pending user APCs */ /* Check for pending user APCs */
mov rcx, gs:[PcCurrentThread] mov rcx, gs:[PcCurrentThread]
HANDLE_USER_APCS rcx, rsp + MAX_SYSCALL_PARAM_SIZE cmp byte ptr [rcx + ThApcState + AsUserApcPending], 0
jz NoUserApcPending
/* Save missing regs in the trap frame */
mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rax], rax
mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rbp], rbp
mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9], rbp
mov rax, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rsp]
mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R8], rax
mov rax, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rip]
mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx], rax
mov rax, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags]
mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R11], rax
xor rax, rax
mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rdx], rax
mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R10], rax
pxor xmm0, xmm0
movdqa [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Xmm0], xmm0
movdqa [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Xmm1], xmm0
movdqa [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Xmm2], xmm0
movdqa [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Xmm3], xmm0
movdqa [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Xmm4], xmm0
movdqa [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Xmm5], xmm0
lea rcx, [rsp + MAX_SYSCALL_PARAM_SIZE]
call KiInitiateUserApc
NoUserApcPending:
/* Disable interrupts for return */ /* Disable interrupts for return */
cli cli
@ -1148,9 +1174,6 @@ PUBLIC KiInitiateUserApc
/* Generate a KEXCEPTION_FRAME on the stack */ /* Generate a KEXCEPTION_FRAME on the stack */
GENERATE_EXCEPTION_FRAME GENERATE_EXCEPTION_FRAME
/* Save rax to not clobber the return for the system call handler */
mov [rsp + ExP1Home], rax
/* Raise IRQL to APC_LEVEL */ /* Raise IRQL to APC_LEVEL */
mov rax, APC_LEVEL mov rax, APC_LEVEL
mov cr8, rax mov cr8, rax
@ -1184,7 +1207,6 @@ deliver_apcs:
mov cr8, rax mov cr8, rax
/* Restore the registers from the KEXCEPTION_FRAME */ /* Restore the registers from the KEXCEPTION_FRAME */
mov rax, [rsp + ExP1Home]
RESTORE_EXCEPTION_STATE RESTORE_EXCEPTION_STATE
/* Return */ /* Return */