[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.
This commit is contained in:
Thomas Faber 2020-05-22 22:34:56 +02:00
parent d40ff3ca98
commit 4f49a9c792
No known key found for this signature in database
GPG key ID: 076E7C3D44720826
2 changed files with 22 additions and 6 deletions

View file

@ -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]

View file

@ -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;