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

commit 45f75d5d320caf7ab1113f0a2cf7c853e9ad4216
Author:     Timo Kreuzer <[email protected]>
AuthorDate: Sat Jun 26 18:49:47 2021 +0200
Commit:     Timo Kreuzer <[email protected]>
CommitDate: Thu Jul 14 18:35:28 2022 +0200

    [NTOS:KE/x64] Handle user faults in KiGeneralProtectionFaultHandler
---
 ntoskrnl/ke/amd64/except.c | 190 ++++++++++++++++++++++++++++++++++++++++++---
 ntoskrnl/ke/amd64/trap.S   |  16 +++-
 sdk/lib/rtl/amd64/unwind.c |   7 +-
 3 files changed, 198 insertions(+), 15 deletions(-)

diff --git a/ntoskrnl/ke/amd64/except.c b/ntoskrnl/ke/amd64/except.c
index dfaee9ed3cc..a04d3038bd9 100644
--- a/ntoskrnl/ke/amd64/except.c
+++ b/ntoskrnl/ke/amd64/except.c
@@ -425,6 +425,184 @@ KiNpxNotAvailableFaultHandler(
     return -1;
 }
 
+static
+BOOLEAN
+KiIsPrivilegedInstruction(PUCHAR Ip, BOOLEAN Wow64)
+{
+    ULONG i;
+
+    /* Handle prefixes */
+    for (i = 0; i < 15; i++)
+    {
+        if (!Wow64)
+        {
+            /* Check for REX prefix */
+            if ((Ip[0] >= 0x40) && (Ip[0] <= 0x4F))
+            {
+                Ip++;
+                continue;
+            }
+        }
+
+        switch (Ip[0])
+        {
+            /* Check prefixes */
+            case 0x26: // ES
+            case 0x2E: // CS / null
+            case 0x36: // SS
+            case 0x3E: // DS
+            case 0x64: // FS
+            case 0x65: // GS
+            case 0x66: // OP
+            case 0x67: // ADDR
+            case 0xF0: // LOCK
+            case 0xF2: // REP
+            case 0xF3: // REP INS/OUTS
+                Ip++;
+                continue;
+        }
+
+        break;
+    }
+
+    if (i == 15)
+    {
+        /* Too many prefixes. Should only happen, when the code was 
concurrently modified. */
+         return FALSE;
+    }
+
+    switch (Ip[0])
+    {
+        case 0xF4: // HLT
+        case 0xFA: // CLI
+        case 0xFB: // STI
+            return TRUE;
+
+        case 0x0F:
+        {
+            switch (Ip[1])
+            {
+                case 0x06: // CLTS
+                case 0x07: // SYSRET
+                case 0x08: // INVD
+                case 0x09: // WBINVD
+                case 0x20: // MOV CR, XXX
+                case 0x21: // MOV DR, XXX
+                case 0x22: // MOV XXX, CR
+                case 0x23: // MOV YYY, DR
+                case 0x30: // WRMSR
+                case 0x32: // RDMSR
+                case 0x33: // RDPMC
+                case 0x35: // SYSEXIT
+                case 0x78: // VMREAD
+                case 0x79: // VMWRITE
+                    return TRUE;
+
+                case 0x00:
+                {
+                    /* Check MODRM Reg field */
+                    switch ((Ip[2] >> 3) & 0x7)
+                    {
+                        case 2: // LLDT
+                        case 3: // LTR
+                            return TRUE;
+                    }
+                    break;
+                }
+
+                case 0x01:
+                {
+                    switch (Ip[2])
+                    {
+                        case 0xC1: // VMCALL
+                        case 0xC2: // VMLAUNCH
+                        case 0xC3: // VMRESUME
+                        case 0xC4: // VMXOFF
+                        case 0xC8: // MONITOR
+                        case 0xC9: // MWAIT
+                        case 0xD1: // XSETBV
+                        case 0xF8: // SWAPGS
+                            return TRUE;
+                    }
+
+                    /* Check MODRM Reg field */
+                    switch ((Ip[2] >> 3) & 0x7)
+                    {
+                        case 2: // LGDT
+                        case 3: // LIDT
+                        case 6: // LMSW
+                        case 7: // INVLPG / SWAPGS / RDTSCP
+                            return TRUE;
+                    }
+                    break;
+                }
+
+                case 0x38:
+                {
+                    switch (Ip[2])
+                    {
+                        case 0x80: // INVEPT
+                        case 0x81: // INVVPID
+                            return TRUE;
+                    }
+                    break;
+                }
+
+                case 0xC7:
+                {
+                    /* Check MODRM Reg field */
+                    switch ((Ip[2] >> 3) & 0x7)
+                    {
+                        case 0x06: // VMPTRLD, VMCLEAR, VMXON
+                        case 0x07: // VMPTRST
+                            return TRUE;
+                    }
+                    break;
+                }
+            }
+
+            break;
+        }
+    }
+
+    return FALSE;
+}
+
+static
+NTSTATUS
+KiGeneralProtectionFaultUserMode(
+    _In_ PKTRAP_FRAME TrapFrame)
+{
+    BOOLEAN Wow64 = TrapFrame->SegCs == KGDT64_R3_CMCODE;
+    PUCHAR InstructionPointer;
+    NTSTATUS Status;
+
+    /* We need to decode the instruction at RIP */
+    InstructionPointer = (PUCHAR)TrapFrame->Rip;
+
+    _SEH2_TRY
+    {
+        /* Probe the instruction address */
+        ProbeForRead(InstructionPointer, 64, 1);
+
+        /* Check if it's a privileged instruction */
+        if (KiIsPrivilegedInstruction(InstructionPointer, Wow64))
+        {
+            Status = STATUS_PRIVILEGED_INSTRUCTION;
+        }
+        else
+        {
+            Status = STATUS_ACCESS_VIOLATION;
+        }
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END
+
+    return Status;
+}
 
 NTSTATUS
 NTAPI
@@ -436,8 +614,7 @@ KiGeneralProtectionFaultHandler(
     /* Check for user-mode GPF */
     if (TrapFrame->SegCs & 3)
     {
-        UNIMPLEMENTED;
-        ASSERT(FALSE);
+        return KiGeneralProtectionFaultUserMode(TrapFrame);
     }
 
     /* Check for lazy segment load */
@@ -454,15 +631,6 @@ KiGeneralProtectionFaultHandler(
         return STATUS_SUCCESS;
     }
 
-    /* Check for nested exception */
-    if ((TrapFrame->Rip >= (ULONG64)KiGeneralProtectionFaultHandler) &&
-        (TrapFrame->Rip < (ULONG64)KiGeneralProtectionFaultHandler))
-    {
-        /* Not implemented */
-        UNIMPLEMENTED;
-        ASSERT(FALSE);
-    }
-
     /* Get Instruction Pointer */
     Instructions = (PUCHAR)TrapFrame->Rip;
 
diff --git a/ntoskrnl/ke/amd64/trap.S b/ntoskrnl/ke/amd64/trap.S
index 1598cef290c..644b4c2032d 100644
--- a/ntoskrnl/ke/amd64/trap.S
+++ b/ntoskrnl/ke/amd64/trap.S
@@ -285,7 +285,7 @@ KiInvalidOpcodeKernel:
     /* Kernel mode fault */
 
     /* Dispatch the exception */
-    DispatchException STATUS_ILLEGAL_INSTRUCTION, 3, 0, 0, 0
+    DispatchException STATUS_ILLEGAL_INSTRUCTION, 0, 0, 0, 0
 
     /* Return */
     ExitTrap TF_SAVE_ALL
@@ -385,8 +385,18 @@ FUNC KiGeneralProtectionFault
     test eax, eax
     jge KiGpfExit
 
-    /* Dispatch the exception */
-    DispatchException eax, 3, 0, 0, 0
+    /* Check for access violation */
+    cmp eax, STATUS_ACCESS_VIOLATION
+    je DispatchAccessViolation
+
+    /* Dispatch privileged instruction fault */
+    DispatchException eax, 0, 0, 0, 0
+    jmp KiGpfFatal
+
+DispatchAccessViolation:
+
+    /* Dispatch access violation */
+    DispatchException eax, 2, 0, -1, 0
 
 KiGpfFatal:
 
diff --git a/sdk/lib/rtl/amd64/unwind.c b/sdk/lib/rtl/amd64/unwind.c
index 49e3740bec4..619d31b6bb9 100644
--- a/sdk/lib/rtl/amd64/unwind.c
+++ b/sdk/lib/rtl/amd64/unwind.c
@@ -701,9 +701,15 @@ RtlpUnwindInternal(
                Note: this can happen after the first frame as the result of an 
exception */
             UnwindContext.Rip = *(DWORD64*)UnwindContext.Rsp;
             UnwindContext.Rsp += sizeof(DWORD64);
+
+            /* Copy the context back for the next iteration */
+            *ContextRecord = UnwindContext;
             continue;
         }
 
+        /* Save Rip before the virtual unwind */
+        DispatcherContext.ControlPc = UnwindContext.Rip;
+
         /* Do a virtual unwind to get the next frame */
         ExceptionRoutine = RtlVirtualUnwind(HandlerType,
                                             ImageBase,
@@ -749,7 +755,6 @@ RtlpUnwindInternal(
                                   sizeof(DispatcherContext));
 
             /* Set up the variable fields of the dispatcher context */
-            DispatcherContext.ControlPc = ContextRecord->Rip;
             DispatcherContext.ImageBase = ImageBase;
             DispatcherContext.FunctionEntry = FunctionEntry;
             DispatcherContext.LanguageHandler = ExceptionRoutine;

Reply via email to