https://git.reactos.org/?p=reactos.git;a=commitdiff;h=4f49a9c792b8334a5ad8d6...
commit 4f49a9c792b8334a5ad8d6daaecd26dde6870f3c Author: Thomas Faber thomas.faber@reactos.org AuthorDate: Fri May 22 22:34:56 2020 +0200 Commit: Thomas Faber thomas.faber@reactos.org CommitDate: Sat Jun 6 08:44:30 2020 +0200
[NTOS:KE] Save ExceptionList in the assembly version of KiEnterTrap. CORE-15723
If SEH is used in a C trap handler, the exception frame will be registered before the call to KiEnterTrap, which means we save the wrong trap handler. We'll therefore also restore this wrong frame for the excepting code, resulting in a stale SEH chain.
We avoid this problem by saving the handler in the assembly trap entry code instead of from C. While SEH in a C trap handler should now theoretically be safe, we still forbid it through asserts in the C KiEnterTrap variants to make any potential future problems more obvious. Should this functionality be needed at some point and deemed safe, these asserts can then be removed. --- ntoskrnl/include/internal/i386/asmmacro.S | 4 ++++ ntoskrnl/include/internal/i386/trap_x.h | 24 ++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/ntoskrnl/include/internal/i386/asmmacro.S b/ntoskrnl/include/internal/i386/asmmacro.S index f7af217cc9f..543ce3f1bc4 100644 --- a/ntoskrnl/include/internal/i386/asmmacro.S +++ b/ntoskrnl/include/internal/i386/asmmacro.S @@ -207,6 +207,10 @@ set_sane_segs: mov fs, ax endif
+ /* Save ExceptionList, since the C handler might use SEH */ + mov eax, fs:[KPCR_EXCEPTION_LIST] + mov [esp + KTRAP_FRAME_EXCEPTION_LIST], eax + #if DBG /* Keep the frame chain intact */ mov eax, [esp + KTRAP_FRAME_EIP] diff --git a/ntoskrnl/include/internal/i386/trap_x.h b/ntoskrnl/include/internal/i386/trap_x.h index 06443c9dc90..cd79c2a40c4 100644 --- a/ntoskrnl/include/internal/i386/trap_x.h +++ b/ntoskrnl/include/internal/i386/trap_x.h @@ -349,8 +349,12 @@ FORCEINLINE VOID KiEnterV86Trap(IN PKTRAP_FRAME TrapFrame) { - /* Save exception list */ - TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList; + PVOID ExceptionList; + + /* Check exception list */ + ExceptionList = KeGetPcr()->NtTib.ExceptionList; + ASSERTMSG("V86 trap handler must not register an SEH frame\n", + ExceptionList == TrapFrame->ExceptionList);
/* Save DR7 and check for debugging */ TrapFrame->Dr7 = __readdr(7); @@ -368,8 +372,12 @@ FORCEINLINE VOID KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame) { - /* Save exception list and terminate it */ - TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList; + PVOID ExceptionList; + + /* Check exception list and terminate it */ + ExceptionList = KeGetPcr()->NtTib.ExceptionList; + ASSERTMSG("Interrupt handler must not register an SEH frame\n", + ExceptionList == TrapFrame->ExceptionList); KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
/* Default to debugging disabled */ @@ -398,8 +406,12 @@ FORCEINLINE VOID KiEnterTrap(IN PKTRAP_FRAME TrapFrame) { - /* Save exception list */ - TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList; + PVOID ExceptionList; + + /* Check exception list */ + ExceptionList = KeGetPcr()->NtTib.ExceptionList; + ASSERTMSG("Trap handler must not register an SEH frame\n", + ExceptionList == TrapFrame->ExceptionList);
/* Default to debugging disabled */ TrapFrame->Dr7 = 0;