[NTOSKRNL]
authorTimo Kreuzer <timo.kreuzer@reactos.org>
Thu, 22 May 2014 22:28:57 +0000 (22:28 +0000)
committerTimo Kreuzer <timo.kreuzer@reactos.org>
Thu, 22 May 2014 22:28:57 +0000 (22:28 +0000)
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

reactos/include/asm/ks386.template.h
reactos/ntoskrnl/include/internal/i386/asmmacro.S
reactos/ntoskrnl/ke/i386/trap.s
reactos/ntoskrnl/ke/i386/traphdlr.c

index 77085d1..77ac3f8 100644 (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),
 
index 2ab3bdf..4a6b009 100644 (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
index 272886d..733451d 100644 (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:
index d98109a..568c489 100644 (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
  */