[NTOS] Fix unwinding through KiThreadStartup

This commit is contained in:
Timo Kreuzer 2022-08-08 09:30:49 +02:00
parent 66aa25b1cd
commit e923912f94
3 changed files with 67 additions and 24 deletions

View file

@ -10,6 +10,7 @@
/* INCLUDES ******************************************************************/ /* INCLUDES ******************************************************************/
#include <ksamd64.inc> #include <ksamd64.inc>
#include <trapamd64.inc>
/* /*
* BOOLEAN * BOOLEAN
@ -70,10 +71,7 @@ PUBLIC KiThreadStartup
* mov [rsp + SfP3Home], r8 * mov [rsp + SfP3Home], r8
* mov [rsp + SfP4Home], r9 * mov [rsp + SfP4Home], r9
*/ */
.allocstack (5 * 8)
/* Terminate the unwind chain, by setting rbp as frame pointer,
which contains 0 */
.setframe rbp, 0
.endprolog .endprolog
/* Clear all the non-volatile registers, so the thread won't be tempted to /* Clear all the non-volatile registers, so the thread won't be tempted to
@ -101,21 +99,50 @@ PUBLIC KiThreadStartup
mov r8, [rsp + SfP3Home] /* ? */ mov r8, [rsp + SfP3Home] /* ? */
call qword ptr [rsp + SfP4Home] /* SystemRoutine */ call qword ptr [rsp + SfP4Home] /* SystemRoutine */
/* The thread returned. If it was a user-thread, we have a return address /* Return to the exit code */
and all is well, otherwise this is very bad. */ add rsp, 5 * 8
mov rcx, [rsp + SfReturn] ret
or rcx, rcx .ENDP
jnz .leave
/* A system thread returned...this is very bad! */ PUBLIC KiInvalidSystemThreadStartupExit
int 3 .PROC KiInvalidSystemThreadStartupExit
.endprolog
.leave: /* This is invalid! */
/* It was a user thread, set our trapframe for the System Call Exit Dispatcher */ int HEX(2C)
lea rcx, [rsp + 6 * 8 + KEXCEPTION_FRAME_LENGTH] nop
.ENDP
PUBLIC KiUserThreadStartupExit
.PROC KiUserThreadStartupExit
.allocstack (KEXCEPTION_FRAME_LENGTH - 8)
.savereg rbp, ExRbp
.savereg rbx, ExRbx
.savereg rdi, ExRdi
.savereg rsi, ExRsi
.savereg r12, ExR12
.savereg r13, ExR13
.savereg r14, ExR14
.savereg r15, ExR15
.savexmm128 xmm6, ExXmm6
.savexmm128 xmm7, ExXmm7
.savexmm128 xmm8, ExXmm8
.savexmm128 xmm9, ExXmm9
.savexmm128 xmm10, ExXmm10
.savexmm128 xmm11, ExXmm11
.savexmm128 xmm12, ExXmm12
.savexmm128 xmm13, ExXmm13
.savexmm128 xmm14, ExXmm14
.savexmm128 xmm15, ExXmm15
.endprolog
/* Restore the exception frame */
RESTORE_EXCEPTION_STATE
/* Point rcx to the trap frame */
lea rcx, [rsp + 8]
/* Return to the trap exit code */ /* Return to the trap exit code */
add rsp, 5 * 8
ret ret
.ENDP .ENDP

View file

@ -13,6 +13,10 @@
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
extern void KiInvalidSystemThreadStartupExit(void);
extern void KiUserThreadStartupExit(void);
extern void KiServiceExit3(void);
typedef struct _KUINIT_FRAME typedef struct _KUINIT_FRAME
{ {
KSWITCH_FRAME CtxSwitchFrame; KSWITCH_FRAME CtxSwitchFrame;
@ -98,8 +102,11 @@ KiInitializeContextThread(IN PKTHREAD Thread,
/* Terminate the Exception Handler List */ /* Terminate the Exception Handler List */
TrapFrame->ExceptionFrame = 0; TrapFrame->ExceptionFrame = 0;
/* We return to ... */ /* KiThreadStartup returns to KiUserThreadStartupExit */
StartFrame->Return = (ULONG64)KiServiceExit2; StartFrame->Return = (ULONG64)KiUserThreadStartupExit;
/* KiUserThreadStartupExit returns to KiServiceExit3 */
InitFrame->ExceptionFrame.Return = (ULONG64)KiServiceExit3;
} }
else else
{ {
@ -121,8 +128,8 @@ KiInitializeContextThread(IN PKTHREAD Thread,
/* No NPX State */ /* No NPX State */
Thread->NpxState = 0xA; Thread->NpxState = 0xA;
/* We have no return address! */ /* This must never return! */
StartFrame->Return = 0; StartFrame->Return = (ULONG64)KiInvalidSystemThreadStartupExit;
} }
/* Set up the Context Switch Frame */ /* Set up the Context Switch Frame */

View file

@ -930,16 +930,27 @@ PUBLIC KiServiceExit2
.PROC KiServiceExit2 .PROC KiServiceExit2
.ENDPROLOG .ENDPROLOG
// FIXME: this should probably also restore an exception frame
mov rsp, rcx
.ENDP
PUBLIC KiServiceExit3
.PROC KiServiceExit3
.PUSHFRAME
.ALLOCSTACK (KTRAP_FRAME_LENGTH - MachineFrameLength)
.ENDPROLOG
#if DBG #if DBG
/* Get the current IRQL and compare it to the trap frame */ /* Get the current IRQL and compare it to the trap frame */
mov rax, cr8 mov rax, cr8
cmp byte ptr [rcx + KTRAP_FRAME_PreviousIrql], al cmp byte ptr [rsp + KTRAP_FRAME_PreviousIrql], al
je KiServiceExit2_ok1 je KiServiceExit2_ok1
int HEX(2C) int HEX(2C)
KiServiceExit2_ok1: KiServiceExit2_ok1:
/* Check if this is a user mode exit */ /* Check if this is a user mode exit */
mov ah, byte ptr [rcx + KTRAP_FRAME_SegCs] mov ah, byte ptr [rsp + KTRAP_FRAME_SegCs]
test ah, 1 test ah, 1
jz KiServiceExit2_kernel jz KiServiceExit2_kernel
@ -951,10 +962,8 @@ KiServiceExit2_ok1:
KiServiceExit2_kernel: KiServiceExit2_kernel:
#endif #endif
mov rbp, rcx
mov rsp, rcx
/* Return */ /* Return */
mov rbp, rsp
ExitTrap TF_SAVE_ALL ExitTrap TF_SAVE_ALL
.ENDP .ENDP