https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a6732905b81bc6c3a3086…
commit a6732905b81bc6c3a3086cd90f493515d2b93486
Author: Timo Kreuzer <timo.kreuzer(a)reactos.org>
AuthorDate: Sun Feb 4 23:44:43 2018 +0100
Commit: Timo Kreuzer <timo.kreuzer(a)reactos.org>
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