https://git.reactos.org/?p=reactos.git;a=commitdiff;h=2a8c680dbe6392fa8f21cb...
commit 2a8c680dbe6392fa8f21cbd44b7641cf4b6b074b Author: Timo Kreuzer timo.kreuzer@reactos.org AuthorDate: Thu Apr 18 16:41:48 2019 +0200 Commit: Timo Kreuzer timo.kreuzer@reactos.org CommitDate: Sat Oct 31 14:23:16 2020 +0100
[NTOS:KE:X64][NTDLL:X64] Implement KiUserExceptionDispatcher and fix KiDispatchExceptionToUser --- dll/ntdll/dispatch/amd64/dispatch.S | 118 +++++++++++++++++++++++++++++++++++- ntoskrnl/ke/amd64/except.c | 47 +++++++------- sdk/include/ndk/amd64/ketypes.h | 12 ++++ 3 files changed, 152 insertions(+), 25 deletions(-)
diff --git a/dll/ntdll/dispatch/amd64/dispatch.S b/dll/ntdll/dispatch/amd64/dispatch.S index 6d132df7755..86fe423ab2c 100644 --- a/dll/ntdll/dispatch/amd64/dispatch.S +++ b/dll/ntdll/dispatch/amd64/dispatch.S @@ -107,11 +107,125 @@ StatusRaise:
.ENDP
+/* + BOOLEAN + NTAPI + RtlDispatchException( + _In_ PEXCEPTION_RECORD ExceptionRecord, + _In_ PCONTEXT ContextRecord); + */ +EXTERN RtlDispatchException:PROC + +/* + NTSTATUS + NTAPI + ZwContinue( + _In_ PCONTEXT Context, + _In_ BOOLEAN TestAlert); + */ +EXTERN ZwContinue:PROC + +/* + NTSTATUS + NTAPI + ZwRaiseException( + _In_ PEXCEPTION_RECORD ExceptionRecord, + _In_ PCONTEXT Context, + _In_ BOOLEAN SearchFrames); + */ +EXTERN ZwRaiseException:PROC + +/* + VOID + NTAPI + RtlRaiseStatus( + _In_ PEXCEPTION_RECORD ExceptionRecord); + */ +EXTERN RtlRaiseException:PROC + +/* + VOID + KiUserExceptionDispatcher( + CONTEXT ContextRecord<rcx>, + PEXCEPTION_RECORD ExceptionRecord<rdx>); + + This function is called with the following stack layout: + CONTEXT ContextRecord <- RSP, RCX + EXCEPTION_RECORD ExceptionRecord <- RDX + ULONG64 Alignment + MACHINE_FRAME MachineFrame + */ PUBLIC KiUserExceptionDispatcher .PROC KiUserExceptionDispatcher - .endprolog - int 3
+ ; The stack is set up with a KUSER_EXCEPTION_STACK + ; The frame ends with a MACHINE_FRAME. + .PUSHFRAME + + ; This is for the alignment, EXCEPTION_RECORD and CONTEXT + .ALLOCSTACK 8 + EXCEPTION_RECORD_LENGTH + CONTEXT_FRAME_LENGTH + .ENDPROLOG + + /* Clear direction flag */ + cld + + /* Dispatch the exception */ + call RtlDispatchException + + /* Check for success */ + or al, al + jz RaiseException + + /* We're fine, continue execution */ + lea rcx, [rsp] ; ContextRecord + mov dl, 0 ; TestAlert + call ZwContinue + + /* Exit */ + jmp Exit + +RaiseException: + + /* Raise the exception */ + lea rcx, [rsp + CONTEXT_FRAME_LENGTH] ; ExceptionRecord + lea rdx, [rsp] ; ContextRecord + xor r8, r8 + call ZwRaiseException + +Exit: + lea rcx, [rsp + CONTEXT_FRAME_LENGTH] ; ExceptionRecord + mov rdx, rax + call KiUserExceptionDispatcherNested + ret + +.ENDP + +/* + VOID + KiUserExceptionDispatcherNested( + _In_ ExceptionRecord<rcx>, + _In_ Status<edx> + ) + */ +.PROC KiUserExceptionDispatcherNested + /* Allocate space for the nested exception record */ + sub rsp, EXCEPTION_RECORD_LENGTH + .ALLOCSTACK EXCEPTION_RECORD_LENGTH + .ENDPROLOG + + /* Set it up */ + mov dword ptr [rsp + ErNumberParameters], 0 + mov dword ptr [rsp + ErExceptionFlags], EXCEPTION_NONCONTINUABLE + mov [rsp + ErExceptionRecord], rcx + mov [rsp + ErExceptionCode], edx + + /* Raise the exception */ + mov rcx, rsp + call RtlRaiseException + + /* Cleanup stack and return */ + add rsp, EXCEPTION_RECORD_LENGTH + ret .ENDP
END diff --git a/ntoskrnl/ke/amd64/except.c b/ntoskrnl/ke/amd64/except.c index ed0757d84fb..23ff7e016a9 100644 --- a/ntoskrnl/ke/amd64/except.c +++ b/ntoskrnl/ke/amd64/except.c @@ -100,10 +100,8 @@ KiDispatchExceptionToUser( IN PEXCEPTION_RECORD ExceptionRecord) { EXCEPTION_RECORD LocalExceptRecord; - ULONG Size; ULONG64 UserRsp; - PCONTEXT UserContext; - PEXCEPTION_RECORD UserExceptionRecord; + PKUSER_EXCEPTION_STACK UserStack;
/* Make sure we have a valid SS */ if (TrapFrame->SegSs != (KGDT64_R3_DATA | RPL_MASK)) @@ -115,27 +113,29 @@ KiDispatchExceptionToUser( ExceptionRecord = &LocalExceptRecord; }
- /* Calculate the size of the exception record */ - Size = FIELD_OFFSET(EXCEPTION_RECORD, ExceptionInformation) + - ExceptionRecord->NumberParameters * sizeof(ULONG64); - /* Get new stack pointer and align it to 16 bytes */ - UserRsp = (Context->Rsp - Size - sizeof(CONTEXT)) & ~15; + UserRsp = (Context->Rsp - sizeof(KUSER_EXCEPTION_STACK)) & ~15;
- /* Get pointers to the usermode context and exception record */ - UserContext = (PVOID)UserRsp; - UserExceptionRecord = (PVOID)(UserRsp + sizeof(CONTEXT)); + /* Get pointer to the usermode context, exception record and machine frame */ + UserStack = (PKUSER_EXCEPTION_STACK)UserRsp;
/* Set up the user-stack */ _SEH2_TRY { - /* Probe stack and copy Context */ - ProbeForWrite(UserContext, sizeof(CONTEXT), sizeof(ULONG64)); - *UserContext = *Context; - - /* Probe stack and copy exception record */ - ProbeForWrite(UserExceptionRecord, Size, sizeof(ULONG64)); - *UserExceptionRecord = *ExceptionRecord; + /* Probe the user stack frame and zero it out */ + ProbeForWrite(UserStack, sizeof(*UserStack), TYPE_ALIGNMENT(KUSER_EXCEPTION_STACK)); + RtlZeroMemory(UserStack, sizeof(*UserStack)); + + /* Copy Context and ExceptionFrame */ + UserStack->Context = *Context; + UserStack->ExceptionRecord = *ExceptionRecord; + + /* Setup the machine frame */ + UserStack->MachineFrame.Rip = Context->Rip; + UserStack->MachineFrame.SegCs = Context->SegCs; + UserStack->MachineFrame.EFlags = Context->EFlags; + UserStack->MachineFrame.Rsp = Context->Rsp; + UserStack->MachineFrame.SegSs = Context->SegSs; } _SEH2_EXCEPT((LocalExceptRecord = *_SEH2_GetExceptionInformation()->ExceptionRecord), EXCEPTION_EXECUTE_HANDLER) @@ -148,8 +148,8 @@ KiDispatchExceptionToUser( _SEH2_END;
/* Now set the two params for the user-mode dispatcher */ - TrapFrame->Rcx = (ULONG64)UserContext; - TrapFrame->Rdx = (ULONG64)UserExceptionRecord; + TrapFrame->Rcx = (ULONG64)&UserStack->ExceptionRecord; + TrapFrame->Rdx = (ULONG64)&UserStack->Context;
/* Set new Stack Pointer */ TrapFrame->Rsp = UserRsp; @@ -346,9 +346,10 @@ KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
/* Forward exception to user mode debugger */ if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) return; - - //KiDispatchExceptionToUser() - __debugbreak(); + + /* Forward exception to user mode (does not return) */ + KiDispatchExceptionToUser(TrapFrame, &Context, ExceptionRecord); + NT_ASSERT(FALSE); }
/* Try second chance */ diff --git a/sdk/include/ndk/amd64/ketypes.h b/sdk/include/ndk/amd64/ketypes.h index d2c4da16cc8..c989b4be0ca 100644 --- a/sdk/include/ndk/amd64/ketypes.h +++ b/sdk/include/ndk/amd64/ketypes.h @@ -998,6 +998,18 @@ typedef struct _UCALLOUT_FRAME MACHINE_FRAME MachineFrame; } UCALLOUT_FRAME, *PUCALLOUT_FRAME; // size = 0x0058
+// +// Stack frame layout for KiUserExceptionDispatcher +// The name is totally made up +// +typedef struct _KUSER_EXCEPTION_STACK +{ + CONTEXT Context; + EXCEPTION_RECORD ExceptionRecord; + ULONG64 Alignment; + MACHINE_FRAME MachineFrame; +} KUSER_EXCEPTION_STACK, * PKUSER_EXCEPTION_STACK; + typedef struct _DISPATCHER_CONTEXT { ULONG64 ControlPc;