From 389bdb30ca9cfb4b4fec05f3538e0fce9b89bd75 Mon Sep 17 00:00:00 2001 From: Thomas Faber Date: Fri, 14 Apr 2017 11:18:22 +0000 Subject: [PATCH] [NTOS:KE] - Gracefully handle page faults during V86 code execution. This is a bit of a hack because with our limited use of V86 code it is unclear how a page fault can even occur. CORE-12993 #resolve svn path=/trunk/; revision=74305 --- reactos/ntoskrnl/include/internal/i386/ke.h | 6 +++ reactos/ntoskrnl/ke/i386/traphdlr.c | 14 +++++- reactos/ntoskrnl/vdm/vdmexec.c | 47 +++++++++++++++++++-- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/i386/ke.h b/reactos/ntoskrnl/include/internal/i386/ke.h index 5af888b7e07..c7c48eaf5fc 100644 --- a/reactos/ntoskrnl/include/internal/i386/ke.h +++ b/reactos/ntoskrnl/include/internal/i386/ke.h @@ -480,6 +480,12 @@ VdmDispatchBop( IN PKTRAP_FRAME TrapFrame ); +BOOLEAN +NTAPI +VdmDispatchPageFault( + _In_ PKTRAP_FRAME TrapFrame +); + BOOLEAN FASTCALL KiVdmOpcodePrefix( diff --git a/reactos/ntoskrnl/ke/i386/traphdlr.c b/reactos/ntoskrnl/ke/i386/traphdlr.c index 4dccea4ca81..be5dd31ef05 100644 --- a/reactos/ntoskrnl/ke/i386/traphdlr.c +++ b/reactos/ntoskrnl/ke/i386/traphdlr.c @@ -1304,8 +1304,20 @@ KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame) UNIMPLEMENTED_FATAL(); } #endif + /* Check for VDM trap */ - ASSERT((KiVdmTrap(TrapFrame)) == FALSE); + if (KiVdmTrap(TrapFrame)) + { + DPRINT1("VDM PAGE FAULT at %lx:%lx for address %lx\n", + TrapFrame->SegCs, TrapFrame->Eip, Cr2); + if (VdmDispatchPageFault(TrapFrame)) + { + /* Return and end VDM execution */ + DPRINT1("VDM page fault with status 0x%lx resolved\n", Status); + KiEoiHelper(TrapFrame); + } + DPRINT1("VDM page fault with status 0x%lx NOT resolved\n", Status); + } /* Either kernel or user trap (non VDM) so dispatch exception */ if (Status == STATUS_ACCESS_VIOLATION) diff --git a/reactos/ntoskrnl/vdm/vdmexec.c b/reactos/ntoskrnl/vdm/vdmexec.c index cdcd31347c4..8d8ce7a248a 100644 --- a/reactos/ntoskrnl/vdm/vdmexec.c +++ b/reactos/ntoskrnl/vdm/vdmexec.c @@ -239,7 +239,7 @@ VdmpStartExecution(VOID) KeLowerIrql(OldIrql); return STATUS_INVALID_SYSTEM_SERVICE; } - + /* Now do the VDM Swap */ VdmSwapContext(VdmFrame, &VdmTib->MonitorContext, &VdmContext); @@ -269,7 +269,7 @@ VdmEndExecution(IN PKTRAP_FRAME TrapFrame, /* Make a copy of the monitor context */ Context = VdmTib->MonitorContext; - + /* Check if V86 mode was enabled or the trap was edited */ if ((Context.EFlags & EFLAGS_V86_MASK) || (Context.SegCs & FRAME_EDITED)) { @@ -291,7 +291,7 @@ VdmEndExecution(IN PKTRAP_FRAME TrapFrame, /* Remove real IF flag */ VdmTib->VdmContext.EFlags &= ~EFLAGS_INTERRUPT_MASK; } - + /* Turn off VIP and VIF */ TrapFrame->EFlags &= ~(EFLAGS_VIP | EFLAGS_VIF); VdmTib->VdmContext.EFlags &= ~(EFLAGS_VIP | EFLAGS_VIF); @@ -362,4 +362,45 @@ VdmDispatchBop(IN PKTRAP_FRAME TrapFrame) return TRUE; } +BOOLEAN +NTAPI +VdmDispatchPageFault( + _In_ PKTRAP_FRAME TrapFrame) +{ + NTSTATUS Status; + PVDM_TIB VdmTib; + + PAGED_CODE(); + + /* Get the VDM TIB so we can terminate V86 execution */ + Status = VdmpGetVdmTib(&VdmTib); + if (!NT_SUCCESS(Status)) + { + /* Not a proper VDM fault, keep looking */ + DPRINT1("VdmDispatchPageFault: no VDM TIB, Vdm=%p\n", NtCurrentTeb()->Vdm); + return FALSE; + } + + /* Must be coming from V86 code */ + ASSERT(TrapFrame->EFlags & EFLAGS_V86_MASK); + + _SEH2_TRY + { + /* Fill out a VDM Event */ + VdmTib->EventInfo.Event = VdmMemAccess; + VdmTib->EventInfo.InstructionSize = 0; + + /* End VDM Execution */ + VdmEndExecution(TrapFrame, VdmTib); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Status = _SEH2_GetExceptionCode(); + } + _SEH2_END; + + /* Consider the exception handled if we succeeded */ + DPRINT1("VdmDispatchPageFault EFlags %lx exit with 0x%lx\n", TrapFrame->EFlags, Status); + return NT_SUCCESS(Status); +} -- 2.17.1