https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a6732905b81bc6c3a3086cd90f493515d2b93486

commit a6732905b81bc6c3a3086cd90f493515d2b93486
Author:     Timo Kreuzer <[email protected]>
AuthorDate: Sun Feb 4 23:44:43 2018 +0100
Commit:     Timo Kreuzer <[email protected]>
CommitDate: Sat Oct 31 14:23:16 2020 +0100

    [NTOS:KE:X64] Implement KiConvertToGuiThread, KeSwitchKernelStack and 
support for win32k syscalls in KiSystemCallHandler
---
 ntoskrnl/ke/amd64/stubs.c | 102 +++++++++++++++++++++++++++++++++++++++++++---
 ntoskrnl/ke/amd64/trap.S  |  45 ++++++++++++++++++++
 2 files changed, 141 insertions(+), 6 deletions(-)

diff --git a/ntoskrnl/ke/amd64/stubs.c b/ntoskrnl/ke/amd64/stubs.c
index b5ae60a550d..09d9e9ff1b0 100644
--- a/ntoskrnl/ke/amd64/stubs.c
+++ b/ntoskrnl/ke/amd64/stubs.c
@@ -8,6 +8,7 @@
 /* INCLUDES ******************************************************************/
 
 #include <ntoskrnl.h>
+#include <fltkernel.h>
 
 #define NDEBUG
 #include <debug.h>
@@ -17,6 +18,10 @@ KiRetireDpcListInDpcStack(
     PKPRCB Prcb,
     PVOID DpcStack);
 
+NTSTATUS
+KiConvertToGuiThread(
+    VOID);
+
 VOID
 NTAPI
 KiDpcInterruptHandler(VOID)
@@ -86,13 +91,66 @@ KeZeroPages(IN PVOID Address,
     RtlZeroMemory(Address, Size);
 }
 
+PVOID
+KiSwitchKernelStackHelper(
+    LONG_PTR StackOffset,
+    PVOID OldStackBase);
+
 PVOID
 NTAPI
 KeSwitchKernelStack(PVOID StackBase, PVOID StackLimit)
 {
-    UNIMPLEMENTED;
-    __debugbreak();
-    return NULL;
+    PKTHREAD CurrentThread;
+    PVOID OldStackBase;
+    LONG_PTR StackOffset;
+    SIZE_T StackSize;
+
+    /* Get the current thread */
+    CurrentThread = KeGetCurrentThread();
+
+    /* Save the old stack base */
+    OldStackBase = CurrentThread->StackBase;
+
+    /* Get the size of the current stack */
+    StackSize = (ULONG_PTR)CurrentThread->StackBase - 
CurrentThread->StackLimit;
+    ASSERT(StackSize <= (ULONG_PTR)StackBase - (ULONG_PTR)StackLimit);
+
+    /* Copy the current stack contents to the new stack */
+    RtlCopyMemory((PUCHAR)StackBase - StackSize,
+                  (PVOID)CurrentThread->StackLimit,
+                  StackSize);
+
+    /* Calculate the offset between the old and the new stack */
+    StackOffset = (PUCHAR)StackBase - (PUCHAR)CurrentThread->StackBase;
+
+    /* Disable interrupts while messing with the stack */
+    _disable();
+
+    /* Set the new trap frame */
+    CurrentThread->TrapFrame = (PKTRAP_FRAME)Add2Ptr(CurrentThread->TrapFrame,
+                                                     StackOffset);
+
+    /* Set the new initial stack */
+    CurrentThread->InitialStack = Add2Ptr(CurrentThread->InitialStack,
+                                          StackOffset);
+
+    /* Set the new stack limits */
+    CurrentThread->StackBase = StackBase;
+    CurrentThread->StackLimit = (ULONG_PTR)StackLimit;
+    CurrentThread->LargeStack = TRUE;
+
+    /* Adjust the PCR fields */
+    __addgsqword(FIELD_OFFSET(KPCR, NtTib.StackBase), StackOffset);
+    __addgsqword(FIELD_OFFSET(KIPCR, Prcb.RspBase), StackOffset);
+
+    /* Finally switch RSP to the new stack.
+       We pass OldStackBase to make sure it is not lost. */
+    OldStackBase = KiSwitchKernelStackHelper(StackOffset, OldStackBase);
+
+    /* Reenable interrupts */
+    _enable();
+
+    return OldStackBase;
 }
 
 NTSTATUS
@@ -313,9 +371,7 @@ KiSystemCallHandler(
     PULONG64 KernelParams, UserParams;
     ULONG ServiceNumber, Offset, Count;
     ULONG64 UserRsp;
-
-    DPRINT("Syscall #%ld\n", TrapFrame->Rax);
-    //__debugbreak();
+    NTSTATUS Status;
 
     /* Increase system call count */
     __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1);
@@ -355,6 +411,40 @@ KiSystemCallHandler(
     /* Get descriptor table */
     DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
 
+    /* Validate the system call number */
+    if (ServiceNumber >= DescriptorTable->Limit)
+    {
+        /* Check if this is a GUI call */
+        if (!(Offset & SERVICE_TABLE_TEST))
+        {
+            /* Fail the call */
+            TrapFrame->Rax = STATUS_INVALID_SYSTEM_SERVICE;
+            return (PVOID)NtSyscallFailure;
+        }
+
+        /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
+        Status = KiConvertToGuiThread();
+
+        /* Reload trap frame and descriptor table pointer from new stack */
+        TrapFrame = *(volatile PVOID*)&Thread->TrapFrame;
+        DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable 
+ Offset);
+
+        if (!NT_SUCCESS(Status))
+        {
+            /* Set the last error and fail */
+            TrapFrame->Rax = Status;
+            return (PVOID)NtSyscallFailure;
+        }
+
+        /* Validate the system call number again */
+        if (ServiceNumber >= DescriptorTable->Limit)
+        {
+            /* Fail the call */
+            TrapFrame->Rax = STATUS_INVALID_SYSTEM_SERVICE;
+            return (PVOID)NtSyscallFailure;
+        }
+    }
+
     /* Get stack bytes and calculate argument count */
     Count = DescriptorTable->Number[ServiceNumber] / 8;
 
diff --git a/ntoskrnl/ke/amd64/trap.S b/ntoskrnl/ke/amd64/trap.S
index 75707e1d72d..29f3e4b46e6 100644
--- a/ntoskrnl/ke/amd64/trap.S
+++ b/ntoskrnl/ke/amd64/trap.S
@@ -20,6 +20,7 @@ EXTERN KiGeneralProtectionFaultHandler:PROC
 EXTERN KiXmmExceptionHandler:PROC
 EXTERN KiDeliverApc:PROC
 EXTERN KiDpcInterruptHandler:PROC
+EXTERN PsConvertToGuiThread:PROC
 
 #ifdef _WINKD_
 EXTERN KdSetOwedBreakpoints:PROC
@@ -892,6 +893,28 @@ FUNC KiZwSystemService
 
 ENDFUNC
 
+PUBLIC KiConvertToGuiThread
+FUNC KiConvertToGuiThread
+
+    push rbp
+    .pushreg rbp
+    sub rsp, 32
+    .allocstack 32
+    .endprolog
+
+    /* Call the worker function */
+    call PsConvertToGuiThread
+
+    /* Adjust rsp */
+    add rsp, 32
+
+    /* Restore rbp */
+    pop rbp
+
+    /* return to the caller */
+    ret
+
+ENDFUNC
 
 KiExitToUserApc:
     int 3
@@ -934,6 +957,28 @@ KiInitializeSegments:
     mov gs, ax
     ret
 
+/*!
+ * VOID
+ * KiSwitchKernelStackHelper(
+ *     LONG_PTR StackOffset,
+ *     PVOID OldStackBase);
+ */
+PUBLIC KiSwitchKernelStackHelper
+KiSwitchKernelStackHelper:
+    
+    /* Pop return address from the current stack */
+    pop rax
+
+    /* Switch to new stack */
+    lea rsp, [rsp + rcx]
+
+    /* Push return address on the new stack */
+    push rax
+
+    /* Return on new stack */
+    mov rax, rdx
+    ret;
+
 
 #ifdef _MSC_VER
 #undef lgdt

Reply via email to