mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[NTOS:KE/x64] Handle user faults in KiGeneralProtectionFaultHandler
This commit is contained in:
parent
f659ac5201
commit
45f75d5d32
3 changed files with 198 additions and 15 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue