[NTOSKRNL]

When a user mode debugger has single stepping enabled and steps over a sysenter instruction, you are obviously not supposed to enter the kernel debugger on the syscall entry handler. But exactly this happened on reactos. This was because the sysenter instruction doesn't disable single stepping, so we need to handle this special case manually in the single stepping handler (which we didn't). We now check if the single step comes from KiFastCallEntry and when it does, disable single stepping in the current (nested) trap frame and return back to a secondary fast call entry. The 2nd entrypoint will make sure to re-enable the single step flag in EFLAGS before returning to usermode.
To make this actually work, the asm entry stub itself needs to handle saving of eflags, so some trap frame modification from KiFastCallEntryHandler was moved into the asm stub. Since the amount of asm instructions is rather small (10 instructions, pretty straight forward) I moved everything from KiSystemServiceHandler to the asm stub and killed KiFastCallEntryHandler entirely, calling KiSystemServiceHandler instead.
Now stepping over a sysenter instruction works with OllyDbg without breaking into the kernel debugger. CORE-8057 #resolve

svn path=/trunk/; revision=63420
This commit is contained in:
Timo Kreuzer 2014-05-22 22:28:57 +00:00
parent ccd49a5b8a
commit df7e3fde89
4 changed files with 53 additions and 45 deletions

View file

@ -347,7 +347,7 @@ OFFSET(CONTEXT_SEGSS, CONTEXT, SegSs),
//OFFSET(CONTEXT_FLOAT_SAVE_STATUS_WORD CONTEXT_FLOAT_SAVE + FP_STATUS_WORD
//OFFSET(CONTEXT_FLOAT_SAVE_TAG_WORD CONTEXT_FLOAT_SAVE + FP_TAG_WORD
//OFFSET(CONTEXT_FRAME_LENGTH 0x2D0
SIZE(CONTEXT_FRAME_LENGTH, CONTEXT),
SIZE(CONTEXT_FRAME_LENGTH, CONTEXT),
HEADER("FIBER"),
OFFSET(FIBER_PARAMETER, FIBER, Parameter),
@ -387,7 +387,7 @@ OFFSET(EXCEPTION_RECORD_NUMBER_PARAMETERS, EXCEPTION_RECORD, NumberParameters),
OFFSET(EXCEPTION_RECORD_EXCEPTION_ADDRESS, EXCEPTION_RECORD, ExceptionAddress),
SIZE(SIZEOF_EXCEPTION_RECORD, EXCEPTION_RECORD),
CONSTANT(EXCEPTION_RECORD_LENGTH),
//#define EXCEPTION_RECORD_LENGTH 0x50
HEADER("KTHREAD"),
@ -463,6 +463,5 @@ CONSTANT(EXCEPTION_EXECUTE_HANDLER),
CONSTANT(STATUS_CALLBACK_POP_STACK),
CONSTANT(CONTEXT_ALIGNED_SIZE),
CONSTANT(PROCESSOR_FEATURE_FXSR),
CONSTANT(KUSER_SHARED_SYSCALL_RET),

View file

@ -83,7 +83,7 @@ MACRO(KiEnterTrap, Flags)
if (Flags AND KI_FAST_SYSTEM_CALL)
/* SYSENTER requires us to build a complete ring transition trap frame */
FrameSize = KTRAP_FRAME_V86_ES
FrameSize = KTRAP_FRAME_EIP
/* Fixup fs. cx is free to clobber */
mov cx, KGDT_R0_PCR
@ -95,6 +95,13 @@ MACRO(KiEnterTrap, Flags)
/* Get a stack pointer */
mov esp, [ecx + KTSS_ESP0]
/* Set up a fake hardware trap frame */
push KGDT_R3_DATA or RPL_MASK
push edx
pushfd
push KGDT_R3_CODE or RPL_MASK
push dword ptr ds:[KUSER_SHARED_SYSCALL_RET]
elseif (Flags AND KI_SOFTWARE_TRAP)
/* Software traps need a complete non-ring transition trap frame */
@ -183,7 +190,19 @@ set_sane_segs:
mov es, ax
/* Fast system calls have fs already fixed */
if (NOT (Flags AND KI_FAST_SYSTEM_CALL))
if (Flags AND KI_FAST_SYSTEM_CALL)
/* Enable interrupts and set a sane FS value */
or dword ptr [esp + KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
mov dword ptr [esp + KTRAP_FRAME_FS], KGDT_R3_TEB or RPL_MASK
/* Set sane active EFLAGS */
push 2
popfd
/* Point edx to the usermode parameters */
add edx, 8
else
/* Otherwise fix fs now */
mov ax, KGDT_R0_PCR
mov fs, ax

View file

@ -142,14 +142,20 @@ PUBLIC _KiSystemService
KiCallHandler @KiSystemServiceHandler@8
.ENDP
EXTERN @KiFastCallEntryHandler@8:PROC
PUBLIC _KiFastCallEntry
.PROC _KiFastCallEntry
FPO 0, 0, 0, 0, 1, FRAME_TRAP
KiEnterTrap (KI_FAST_SYSTEM_CALL OR KI_NONVOLATILES_ONLY OR KI_DONT_SAVE_SEGS)
KiCallHandler @KiFastCallEntryHandler@8
KiCallHandler @KiSystemServiceHandler@8
.ENDP
PUBLIC _KiFastCallEntryWithSingleStep
.PROC _KiFastCallEntryWithSingleStep
FPO 0, 0, 0, 0, 1, FRAME_TRAP
KiEnterTrap (KI_FAST_SYSTEM_CALL OR KI_NONVOLATILES_ONLY OR KI_DONT_SAVE_SEGS)
or dword ptr [ecx + KTRAP_FRAME_EFLAGS], EFLAGS_TF
KiCallHandler @KiSystemServiceHandler@8
.ENDP
PUBLIC _KiEndUnexpectedRange@0
_KiEndUnexpectedRange@0:

View file

@ -12,6 +12,9 @@
#define NDEBUG
#include <debug.h>
VOID KiFastCallEntry(VOID);
VOID KiFastCallEntryWithSingleStep(VOID);
/* GLOBALS ********************************************************************/
UCHAR KiTrapPrefixTable[] =
@ -417,13 +420,26 @@ KiTrap01Handler(IN PKTRAP_FRAME TrapFrame)
{
/* Save trap frame */
KiEnterTrap(TrapFrame);
/* Check for VDM trap */
ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
/* Check if this was a single step after sysenter */
if (TrapFrame->Eip == (ULONG)KiFastCallEntry)
{
/* Disable single stepping */
TrapFrame->EFlags &= ~EFLAGS_TF;
/* Re-enter at the alternative sysenter entry point */
TrapFrame->Eip = (ULONG)KiFastCallEntryWithSingleStep;
/* End this trap */
KiEoiHelper(TrapFrame);
}
/* Enable interrupts if the trap came from user-mode */
if (KiUserTrap(TrapFrame)) _enable();
/* Mask out trap flag and dispatch the exception */
TrapFrame->EFlags &= ~EFLAGS_TF;
KiDispatchException0Args(STATUS_SINGLE_STEP,
@ -1521,11 +1537,11 @@ KiDbgPostServiceHook(ULONG SystemCallNumber, ULONG_PTR Result)
return Result;
}
FORCEINLINE
DECLSPEC_NORETURN
VOID
KiSystemCall(IN PKTRAP_FRAME TrapFrame,
IN PVOID Arguments)
FASTCALL
KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame,
IN PVOID Arguments)
{
PKTHREAD Thread;
PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
@ -1658,38 +1674,6 @@ ExitCall:
KiServiceExit(TrapFrame, Result);
}
DECLSPEC_NORETURN
VOID
FASTCALL
KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame,
IN PVOID Arguments)
{
/* Call the shared handler (inline) */
KiSystemCall(TrapFrame, Arguments);
}
DECLSPEC_NORETURN
VOID
FASTCALL
KiFastCallEntryHandler(IN PKTRAP_FRAME TrapFrame,
IN PVOID Arguments)
{
/* Set up a fake INT Stack and enable interrupts */
TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK;
TrapFrame->HardwareEsp = (ULONG_PTR)Arguments;
TrapFrame->EFlags = __readeflags() | EFLAGS_INTERRUPT_MASK;
TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
TrapFrame->Eip = SharedUserData->SystemCallReturn;
TrapFrame->SegFs = KGDT_R3_TEB | RPL_MASK;
__writeeflags(0x2);
/* Arguments are actually 2 frames down (because of the double indirection) */
Arguments = (PVOID)(TrapFrame->HardwareEsp + 8);
/* Call the shared handler (inline) */
KiSystemCall(TrapFrame, Arguments);
}
/*
* @implemented
*/