[NTOS:KE/x64] Handle NMI vs swapgs race condition

This commit is contained in:
Timo Kreuzer 2024-04-01 21:22:29 +03:00
parent 72fd54a7f4
commit 6ac260dcec
2 changed files with 30 additions and 1 deletions

View File

@ -91,6 +91,10 @@ static __inline__ __attribute__((always_inline)) void __str(unsigned short *Dest
__asm__ __volatile__("str %0" : : "m"(*Destination) : "memory");
}
static __inline__ __attribute__((always_inline)) void __swapgs(void)
{
__asm__ __volatile__("swapgs" : : : "memory");
}
#elif defined(_MSC_VER)
@ -106,6 +110,7 @@ void __ltr(unsigned short Source);
void __str(unsigned short *Destination);
void __swapgs(void);
#else
#error Unknown compiler for inline assembler

View File

@ -89,15 +89,39 @@ KiNmiInterruptHandler(
_In_ PKTRAP_FRAME TrapFrame,
_In_ PKEXCEPTION_FRAME ExceptionFrame)
{
BOOLEAN ManualSwapGs = FALSE;
/* Check if the NMI came from kernel mode */
if ((TrapFrame->SegCs & MODE_MASK) == 0)
{
/* Check if GS base is already kernel mode. This is needed, because
we might be interrupted during an interrupt/exception from user-mode
before the swapgs instruction. */
if ((LONG64)__readmsr(MSR_GS_BASE) >= 0)
{
/* Swap GS to kernel */
__swapgs();
ManualSwapGs = TRUE;
}
}
/* Check if this is a freeze */
if (KiProcessorFreezeHandler(TrapFrame, ExceptionFrame))
{
/* NMI was handled */
return;
goto Exit;
}
/* Handle the NMI */
KiHandleNmi();
Exit:
/* Check if we need to swap GS back */
if (ManualSwapGs)
{
/* Swap GS back to user */
__swapgs();
}
}
#define MAX_SYSCALL_PARAMS 16