From: Timo Kreuzer Date: Thu, 22 May 2014 22:28:57 +0000 (+0000) Subject: [NTOSKRNL] X-Git-Tag: backups/0.3.17@66124~1154 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=df7e3fde891a80edffbadb5dfd1f80d8bbd226d4 [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 --- diff --git a/reactos/include/asm/ks386.template.h b/reactos/include/asm/ks386.template.h index 77085d1bcc4..77ac3f8c306 100644 --- a/reactos/include/asm/ks386.template.h +++ b/reactos/include/asm/ks386.template.h @@ -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), diff --git a/reactos/ntoskrnl/include/internal/i386/asmmacro.S b/reactos/ntoskrnl/include/internal/i386/asmmacro.S index 2ab3bdfd6ff..4a6b009d5fc 100644 --- a/reactos/ntoskrnl/include/internal/i386/asmmacro.S +++ b/reactos/ntoskrnl/include/internal/i386/asmmacro.S @@ -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 diff --git a/reactos/ntoskrnl/ke/i386/trap.s b/reactos/ntoskrnl/ke/i386/trap.s index 272886d4891..733451d7db3 100644 --- a/reactos/ntoskrnl/ke/i386/trap.s +++ b/reactos/ntoskrnl/ke/i386/trap.s @@ -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: diff --git a/reactos/ntoskrnl/ke/i386/traphdlr.c b/reactos/ntoskrnl/ke/i386/traphdlr.c index d98109a21ac..568c4892d42 100644 --- a/reactos/ntoskrnl/ke/i386/traphdlr.c +++ b/reactos/ntoskrnl/ke/i386/traphdlr.c @@ -12,6 +12,9 @@ #define NDEBUG #include +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 */