https://git.reactos.org/?p=reactos.git;a=commitdiff;h=4f49a9c792b8334a5ad8d…
commit 4f49a9c792b8334a5ad8d6daaecd26dde6870f3c
Author: Thomas Faber <thomas.faber(a)reactos.org>
AuthorDate: Fri May 22 22:34:56 2020 +0200
Commit: Thomas Faber <thomas.faber(a)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;