2006-11-08 11:47:44 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS Kernel
|
|
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
|
|
* FILE: ntoskrnl/ke/i386/usercall.c
|
|
|
|
* PURPOSE: User-mode Callout Mechanisms (APC and Win32K Callbacks)
|
|
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
|
|
|
|
#include <ntoskrnl.h>
|
|
|
|
#define NDEBUG
|
2008-08-30 16:31:06 +00:00
|
|
|
#include <debug.h>
|
2006-11-08 11:47:44 +00:00
|
|
|
|
2007-11-05 20:02:58 +00:00
|
|
|
extern PGDI_BATCHFLUSH_ROUTINE KeGdiFlushUserBatch;
|
2007-11-05 17:27:25 +00:00
|
|
|
|
2006-11-08 11:47:44 +00:00
|
|
|
/* PRIVATE FUNCTIONS *********************************************************/
|
|
|
|
|
|
|
|
/*++
|
|
|
|
* @name KiInitializeUserApc
|
|
|
|
*
|
|
|
|
* Prepares the Context for a User-Mode APC called through NTDLL.DLL
|
|
|
|
*
|
|
|
|
* @param Reserved
|
|
|
|
* Pointer to the Exception Frame on non-i386 builds.
|
|
|
|
*
|
|
|
|
* @param TrapFrame
|
|
|
|
* Pointer to the Trap Frame.
|
|
|
|
*
|
|
|
|
* @param NormalRoutine
|
|
|
|
* Pointer to the NormalRoutine to call.
|
|
|
|
*
|
|
|
|
* @param NormalContext
|
|
|
|
* Pointer to the context to send to the Normal Routine.
|
|
|
|
*
|
|
|
|
* @param SystemArgument[1-2]
|
|
|
|
* Pointer to a set of two parameters that contain untyped data.
|
|
|
|
*
|
|
|
|
* @return None.
|
|
|
|
*
|
|
|
|
* @remarks None.
|
|
|
|
*
|
|
|
|
*--*/
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame,
|
|
|
|
IN PKTRAP_FRAME TrapFrame,
|
|
|
|
IN PKNORMAL_ROUTINE NormalRoutine,
|
|
|
|
IN PVOID NormalContext,
|
|
|
|
IN PVOID SystemArgument1,
|
|
|
|
IN PVOID SystemArgument2)
|
|
|
|
{
|
|
|
|
CONTEXT Context;
|
|
|
|
ULONG_PTR Stack, AlignedEsp;
|
|
|
|
ULONG ContextLength;
|
|
|
|
EXCEPTION_RECORD SehExceptRecord;
|
|
|
|
|
|
|
|
/* Don't deliver APCs in V86 mode */
|
- Fix critical bugs in exception handling: Unwinding was completely broken, using the wrong SEH protector to detect collided unwinding. The correct protector itself also had a broken check.
- Fix architectural bug in the entire TrapFrame<->Context conversion system and Ring Privilege Transitions (Inter-ring and intra-ring) which was lacking proper sanitation and validation of segments, flags and debug registers. Among other things, IOPL is now respected, CS is not KGDT_R0_CODE | RPL_MASK anymore, and the GPF code is now properly being called. This completely fixes exception handling being totally broken and crashing firefox installer, mirc, and other applications.
- Rewrite the page fault handler base code in assembly instead of relying on a broken C routine. Detect VDM, V8086, detecting expected/normal fault in ExpInterlockedPopEntrySList and faults in the system handler code. Rewrite MmAccessFault to be the main function that calls out to other sub-fault functions, and use the same prototype as NT.
- Fix the KGDT boot table to have proper granularity and big flags, and extend it to 256 entries.
- Create proper thread context in RtlInitializeContext and cleanup Rtl Thread routines.
- Remove all int3 and breakpoints from trap handlers, and replace them with a much better "UNHANDLED_PATH" macro which freezes the system, beeps, and displays a message with the line of code that's unhandled. This is to clearly tell the user that something is unhandled, instead of nesting infinite exceptions due to the int3.
- Fix a bug in INT_PROLOG.
- Sanitize EFLAGS and Code Segments in KeContextToTrapFrame and KeTrapFrameToContext.
- Implement KiUpdateDr7 and KiRecordDr7 as well as DR_MASK and other DR-validation macros and functions to protect against DR-vulnerabilites as well as to properly account for each active hardware breakpoint in a per-thread fashion by using the dispatcher header.
- Allow CR0_EM when running in a VDM.
- Fix FPU/NPX Register handling in KeContextToTrapFrame and KeTrapFrameToContext, and also speed it up by manual copying instead of a memory move.
- Properly give IOPL 3 to user-mode threads if they requested it.
- Detect GPF during GPF.
- Detect pagefault with a trap-frame spread over two or more pages and nested.
- Properly sanitize and set correct trap frame in KiInitailizeUserApc.
- Return STATUS_ACCESS_VIOLATION during page faults instead of STATUS_UNSUCESSFUL.
- Fix assert in VdmSwapContext, as well as Code Selector check which was broken.
- Fix delayed object deletion (ObDeferDeleteObject) and the Ob Repear Routine and list.
- Update Kernel Fun.
- BUGBUG: Temporaily hack VMWare to detection to always detect VMWare.
svn path=/trunk/; revision=25238
2006-12-29 18:49:00 +00:00
|
|
|
if (TrapFrame->EFlags & EFLAGS_V86_MASK) return;
|
2006-11-08 11:47:44 +00:00
|
|
|
|
|
|
|
/* Save the full context */
|
|
|
|
Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
|
|
|
|
KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
|
|
|
|
|
|
|
|
/* Protect with SEH */
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_TRY
|
2006-11-08 11:47:44 +00:00
|
|
|
{
|
|
|
|
/* Sanity check */
|
|
|
|
ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode);
|
|
|
|
|
|
|
|
/* Get the aligned size */
|
|
|
|
AlignedEsp = Context.Esp & ~3;
|
|
|
|
ContextLength = CONTEXT_ALIGNED_SIZE + (4 * sizeof(ULONG_PTR));
|
|
|
|
Stack = ((AlignedEsp - 8) & ~3) - ContextLength;
|
|
|
|
|
|
|
|
/* Probe the stack */
|
|
|
|
ProbeForWrite((PVOID)Stack, AlignedEsp - Stack, 1);
|
|
|
|
ASSERT(!(Stack & 3));
|
|
|
|
|
|
|
|
/* Copy data into it */
|
|
|
|
RtlCopyMemory((PVOID)(Stack + (4 * sizeof(ULONG_PTR))),
|
|
|
|
&Context,
|
|
|
|
sizeof(CONTEXT));
|
|
|
|
|
|
|
|
/* Run at APC dispatcher */
|
|
|
|
TrapFrame->Eip = (ULONG)KeUserApcDispatcher;
|
|
|
|
TrapFrame->HardwareEsp = Stack;
|
|
|
|
|
|
|
|
/* Setup Ring 3 state */
|
- Fix critical bugs in exception handling: Unwinding was completely broken, using the wrong SEH protector to detect collided unwinding. The correct protector itself also had a broken check.
- Fix architectural bug in the entire TrapFrame<->Context conversion system and Ring Privilege Transitions (Inter-ring and intra-ring) which was lacking proper sanitation and validation of segments, flags and debug registers. Among other things, IOPL is now respected, CS is not KGDT_R0_CODE | RPL_MASK anymore, and the GPF code is now properly being called. This completely fixes exception handling being totally broken and crashing firefox installer, mirc, and other applications.
- Rewrite the page fault handler base code in assembly instead of relying on a broken C routine. Detect VDM, V8086, detecting expected/normal fault in ExpInterlockedPopEntrySList and faults in the system handler code. Rewrite MmAccessFault to be the main function that calls out to other sub-fault functions, and use the same prototype as NT.
- Fix the KGDT boot table to have proper granularity and big flags, and extend it to 256 entries.
- Create proper thread context in RtlInitializeContext and cleanup Rtl Thread routines.
- Remove all int3 and breakpoints from trap handlers, and replace them with a much better "UNHANDLED_PATH" macro which freezes the system, beeps, and displays a message with the line of code that's unhandled. This is to clearly tell the user that something is unhandled, instead of nesting infinite exceptions due to the int3.
- Fix a bug in INT_PROLOG.
- Sanitize EFLAGS and Code Segments in KeContextToTrapFrame and KeTrapFrameToContext.
- Implement KiUpdateDr7 and KiRecordDr7 as well as DR_MASK and other DR-validation macros and functions to protect against DR-vulnerabilites as well as to properly account for each active hardware breakpoint in a per-thread fashion by using the dispatcher header.
- Allow CR0_EM when running in a VDM.
- Fix FPU/NPX Register handling in KeContextToTrapFrame and KeTrapFrameToContext, and also speed it up by manual copying instead of a memory move.
- Properly give IOPL 3 to user-mode threads if they requested it.
- Detect GPF during GPF.
- Detect pagefault with a trap-frame spread over two or more pages and nested.
- Properly sanitize and set correct trap frame in KiInitailizeUserApc.
- Return STATUS_ACCESS_VIOLATION during page faults instead of STATUS_UNSUCESSFUL.
- Fix assert in VdmSwapContext, as well as Code Selector check which was broken.
- Fix delayed object deletion (ObDeferDeleteObject) and the Ob Repear Routine and list.
- Update Kernel Fun.
- BUGBUG: Temporaily hack VMWare to detection to always detect VMWare.
svn path=/trunk/; revision=25238
2006-12-29 18:49:00 +00:00
|
|
|
TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, UserMode);
|
|
|
|
TrapFrame->HardwareSegSs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode);
|
|
|
|
TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode);
|
|
|
|
TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode);
|
|
|
|
TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB, UserMode);
|
2006-11-08 11:47:44 +00:00
|
|
|
TrapFrame->SegGs = 0;
|
- Fix critical bugs in exception handling: Unwinding was completely broken, using the wrong SEH protector to detect collided unwinding. The correct protector itself also had a broken check.
- Fix architectural bug in the entire TrapFrame<->Context conversion system and Ring Privilege Transitions (Inter-ring and intra-ring) which was lacking proper sanitation and validation of segments, flags and debug registers. Among other things, IOPL is now respected, CS is not KGDT_R0_CODE | RPL_MASK anymore, and the GPF code is now properly being called. This completely fixes exception handling being totally broken and crashing firefox installer, mirc, and other applications.
- Rewrite the page fault handler base code in assembly instead of relying on a broken C routine. Detect VDM, V8086, detecting expected/normal fault in ExpInterlockedPopEntrySList and faults in the system handler code. Rewrite MmAccessFault to be the main function that calls out to other sub-fault functions, and use the same prototype as NT.
- Fix the KGDT boot table to have proper granularity and big flags, and extend it to 256 entries.
- Create proper thread context in RtlInitializeContext and cleanup Rtl Thread routines.
- Remove all int3 and breakpoints from trap handlers, and replace them with a much better "UNHANDLED_PATH" macro which freezes the system, beeps, and displays a message with the line of code that's unhandled. This is to clearly tell the user that something is unhandled, instead of nesting infinite exceptions due to the int3.
- Fix a bug in INT_PROLOG.
- Sanitize EFLAGS and Code Segments in KeContextToTrapFrame and KeTrapFrameToContext.
- Implement KiUpdateDr7 and KiRecordDr7 as well as DR_MASK and other DR-validation macros and functions to protect against DR-vulnerabilites as well as to properly account for each active hardware breakpoint in a per-thread fashion by using the dispatcher header.
- Allow CR0_EM when running in a VDM.
- Fix FPU/NPX Register handling in KeContextToTrapFrame and KeTrapFrameToContext, and also speed it up by manual copying instead of a memory move.
- Properly give IOPL 3 to user-mode threads if they requested it.
- Detect GPF during GPF.
- Detect pagefault with a trap-frame spread over two or more pages and nested.
- Properly sanitize and set correct trap frame in KiInitailizeUserApc.
- Return STATUS_ACCESS_VIOLATION during page faults instead of STATUS_UNSUCESSFUL.
- Fix assert in VdmSwapContext, as well as Code Selector check which was broken.
- Fix delayed object deletion (ObDeferDeleteObject) and the Ob Repear Routine and list.
- Update Kernel Fun.
- BUGBUG: Temporaily hack VMWare to detection to always detect VMWare.
svn path=/trunk/; revision=25238
2006-12-29 18:49:00 +00:00
|
|
|
TrapFrame->ErrCode = 0;
|
2006-11-08 11:47:44 +00:00
|
|
|
|
|
|
|
/* Sanitize EFLAGS */
|
- Fix critical bugs in exception handling: Unwinding was completely broken, using the wrong SEH protector to detect collided unwinding. The correct protector itself also had a broken check.
- Fix architectural bug in the entire TrapFrame<->Context conversion system and Ring Privilege Transitions (Inter-ring and intra-ring) which was lacking proper sanitation and validation of segments, flags and debug registers. Among other things, IOPL is now respected, CS is not KGDT_R0_CODE | RPL_MASK anymore, and the GPF code is now properly being called. This completely fixes exception handling being totally broken and crashing firefox installer, mirc, and other applications.
- Rewrite the page fault handler base code in assembly instead of relying on a broken C routine. Detect VDM, V8086, detecting expected/normal fault in ExpInterlockedPopEntrySList and faults in the system handler code. Rewrite MmAccessFault to be the main function that calls out to other sub-fault functions, and use the same prototype as NT.
- Fix the KGDT boot table to have proper granularity and big flags, and extend it to 256 entries.
- Create proper thread context in RtlInitializeContext and cleanup Rtl Thread routines.
- Remove all int3 and breakpoints from trap handlers, and replace them with a much better "UNHANDLED_PATH" macro which freezes the system, beeps, and displays a message with the line of code that's unhandled. This is to clearly tell the user that something is unhandled, instead of nesting infinite exceptions due to the int3.
- Fix a bug in INT_PROLOG.
- Sanitize EFLAGS and Code Segments in KeContextToTrapFrame and KeTrapFrameToContext.
- Implement KiUpdateDr7 and KiRecordDr7 as well as DR_MASK and other DR-validation macros and functions to protect against DR-vulnerabilites as well as to properly account for each active hardware breakpoint in a per-thread fashion by using the dispatcher header.
- Allow CR0_EM when running in a VDM.
- Fix FPU/NPX Register handling in KeContextToTrapFrame and KeTrapFrameToContext, and also speed it up by manual copying instead of a memory move.
- Properly give IOPL 3 to user-mode threads if they requested it.
- Detect GPF during GPF.
- Detect pagefault with a trap-frame spread over two or more pages and nested.
- Properly sanitize and set correct trap frame in KiInitailizeUserApc.
- Return STATUS_ACCESS_VIOLATION during page faults instead of STATUS_UNSUCESSFUL.
- Fix assert in VdmSwapContext, as well as Code Selector check which was broken.
- Fix delayed object deletion (ObDeferDeleteObject) and the Ob Repear Routine and list.
- Update Kernel Fun.
- BUGBUG: Temporaily hack VMWare to detection to always detect VMWare.
svn path=/trunk/; revision=25238
2006-12-29 18:49:00 +00:00
|
|
|
TrapFrame->EFlags = Ke386SanitizeFlags(Context.EFlags, UserMode);
|
|
|
|
|
|
|
|
/* Check if thread has IOPL and force it enabled if so */
|
2008-08-24 15:48:05 +00:00
|
|
|
if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
|
2006-11-08 11:47:44 +00:00
|
|
|
|
|
|
|
/* Setup the stack */
|
|
|
|
*(PULONG_PTR)(Stack + 0 * sizeof(ULONG_PTR)) = (ULONG_PTR)NormalRoutine;
|
|
|
|
*(PULONG_PTR)(Stack + 1 * sizeof(ULONG_PTR)) = (ULONG_PTR)NormalContext;
|
|
|
|
*(PULONG_PTR)(Stack + 2 * sizeof(ULONG_PTR)) = (ULONG_PTR)SystemArgument1;
|
|
|
|
*(PULONG_PTR)(Stack + 3 * sizeof(ULONG_PTR)) = (ULONG_PTR)SystemArgument2;
|
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_EXCEPT((RtlCopyMemory(&SehExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER))
|
2006-11-08 11:47:44 +00:00
|
|
|
{
|
|
|
|
/* Dispatch the exception */
|
2008-11-24 13:40:26 +00:00
|
|
|
SehExceptRecord.ExceptionAddress = (PVOID)TrapFrame->Eip;
|
2006-11-08 11:47:44 +00:00
|
|
|
KiDispatchException(&SehExceptRecord,
|
|
|
|
ExceptionFrame,
|
|
|
|
TrapFrame,
|
|
|
|
UserMode,
|
|
|
|
TRUE);
|
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_END;
|
2006-11-08 11:47:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* PUBLIC FUNCTIONS **********************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
KeUserModeCallback(IN ULONG RoutineIndex,
|
|
|
|
IN PVOID Argument,
|
|
|
|
IN ULONG ArgumentLength,
|
|
|
|
OUT PVOID *Result,
|
|
|
|
OUT PULONG ResultLength)
|
|
|
|
{
|
2007-04-02 15:08:54 +00:00
|
|
|
ULONG_PTR NewStack, OldStack;
|
|
|
|
PULONG UserEsp;
|
2009-08-24 19:58:15 +00:00
|
|
|
NTSTATUS CallbackStatus;
|
2006-11-08 11:47:44 +00:00
|
|
|
PEXCEPTION_REGISTRATION_RECORD ExceptionList;
|
|
|
|
PTEB Teb;
|
|
|
|
ULONG GdiBatchCount = 0;
|
|
|
|
ASSERT(KeGetCurrentThread()->ApcState.KernelApcInProgress == FALSE);
|
|
|
|
ASSERT(KeGetPreviousMode() == UserMode);
|
|
|
|
|
|
|
|
/* Get the current user-mode stack */
|
|
|
|
UserEsp = KiGetUserModeStackAddress();
|
|
|
|
OldStack = *UserEsp;
|
|
|
|
|
|
|
|
/* Enter a SEH Block */
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_TRY
|
2006-11-08 11:47:44 +00:00
|
|
|
{
|
|
|
|
/* Calculate and align the stack size */
|
|
|
|
NewStack = (OldStack - ArgumentLength) & ~3;
|
|
|
|
|
|
|
|
/* Make sure it's writable */
|
|
|
|
ProbeForWrite((PVOID)(NewStack - 6 * sizeof(ULONG_PTR)),
|
|
|
|
ArgumentLength + 6 * sizeof(ULONG_PTR),
|
|
|
|
sizeof(CHAR));
|
|
|
|
|
|
|
|
/* Copy the buffer into the stack */
|
|
|
|
RtlCopyMemory((PVOID)NewStack, Argument, ArgumentLength);
|
|
|
|
|
|
|
|
/* Write the arguments */
|
|
|
|
NewStack -= 24;
|
|
|
|
*(PULONG)NewStack = 0;
|
|
|
|
*(PULONG)(NewStack + 4) = RoutineIndex;
|
|
|
|
*(PULONG)(NewStack + 8) = (NewStack + 24);
|
|
|
|
*(PULONG)(NewStack + 12) = ArgumentLength;
|
|
|
|
|
|
|
|
/* Save the exception list */
|
|
|
|
Teb = KeGetCurrentThread()->Teb;
|
|
|
|
ExceptionList = Teb->Tib.ExceptionList;
|
|
|
|
|
|
|
|
/* Jump to user mode */
|
|
|
|
*UserEsp = NewStack;
|
|
|
|
CallbackStatus = KiCallUserMode(Result, ResultLength);
|
|
|
|
if (CallbackStatus != STATUS_CALLBACK_POP_STACK)
|
|
|
|
{
|
|
|
|
/* Only restore the exception list if we didn't crash in ring 3 */
|
|
|
|
Teb->Tib.ExceptionList = ExceptionList;
|
|
|
|
CallbackStatus = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Otherwise, pop the stack */
|
|
|
|
OldStack = *UserEsp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read the GDI Batch count */
|
|
|
|
GdiBatchCount = Teb->GdiBatchCount;
|
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
2006-11-08 11:47:44 +00:00
|
|
|
{
|
|
|
|
/* Get the SEH exception */
|
2009-08-24 19:58:15 +00:00
|
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
2006-11-08 11:47:44 +00:00
|
|
|
}
|
2008-11-24 13:40:26 +00:00
|
|
|
_SEH2_END;
|
2006-11-08 11:47:44 +00:00
|
|
|
|
|
|
|
/* Check if we have GDI Batch operations */
|
|
|
|
if (GdiBatchCount)
|
|
|
|
{
|
2007-11-05 20:02:58 +00:00
|
|
|
*UserEsp -= 256;
|
|
|
|
KeGdiFlushUserBatch();
|
2006-11-08 11:47:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore stack and return */
|
|
|
|
*UserEsp = OldStack;
|
|
|
|
return CallbackStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|