Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/coreclr/vm/amd64/AsmHelpers.asm
Original file line number Diff line number Diff line change
Expand Up @@ -432,13 +432,15 @@ endif ; _DEBUG
NESTED_ENTRY OnHijackTripThread, _TEXT

; Don't fiddle with this unless you change HijackFrame::UpdateRegDisplay
; and HijackObjectArgs
; and HijackArgs
mov rdx, rsp
push rax ; make room for the real return address (Rip)
push rdx
PUSH_CALLEE_SAVED_REGISTERS
push_vol_reg rax
mov rcx, rsp

alloc_stack 30h ; make extra room for xmm0
alloc_stack 38h ; make extra room for xmm0, argument home slots and align the SP
save_xmm128_postrsp xmm0, 20h


Expand All @@ -448,9 +450,10 @@ NESTED_ENTRY OnHijackTripThread, _TEXT

movdqa xmm0, [rsp + 20h]

add rsp, 30h
add rsp, 38h
pop rax
POP_CALLEE_SAVED_REGISTERS
pop rdx
ret ; return to the correct place, adjusted by our caller
NESTED_END OnHijackTripThread, _TEXT

Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/vm/amd64/cgenamd64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,11 @@ void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD)
pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary.

pRD->pCurrentContext->Rip = m_ReturnAddress;
#ifdef TARGET_WINDOWS
pRD->pCurrentContext->Rsp = m_Args->Rsp;
#else
pRD->pCurrentContext->Rsp = PTR_TO_MEMBER_TADDR(HijackArgs, m_Args, Rip) + sizeof(void *);
#endif

UpdateRegDisplayFromCalleeSavedRegisters(pRD, &(m_Args->Regs));

Expand Down
7 changes: 5 additions & 2 deletions src/coreclr/vm/amd64/cgencpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ struct HijackArgs
ULONG64 Rax;
ULONG64 ReturnValue[1];
};
#else // FEATURE_MULTIREG_RETURN
#else // !FEATURE_MULTIREG_RETURN
union
{
struct
Expand All @@ -475,8 +475,11 @@ struct HijackArgs
};
ULONG64 ReturnValue[2];
};
#endif // TARGET_UNIX
#endif // !FEATURE_MULTIREG_RETURN
CalleeSavedRegisters Regs;
#ifdef TARGET_WINDOWS
ULONG64 Rsp;
#endif
union
{
ULONG64 Rip;
Expand Down
46 changes: 46 additions & 0 deletions src/coreclr/vm/excep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7186,6 +7186,52 @@ LONG WINAPI CLRVectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
}

}
#ifdef TARGET_AMD64

#ifndef STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT
#define STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT ((DWORD)0x80000033L)
#endif

if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_RETURN_ADDRESS_HIJACK_ATTEMPT)
{
HijackArgs hijackArgs;
hijackArgs.Rax = pExceptionInfo->ContextRecord->Rax;
hijackArgs.Rsp = pExceptionInfo->ContextRecord->Rsp;

bool areCetShadowStacksEnabled = Thread::AreCetShadowStacksEnabled();
if (areCetShadowStacksEnabled)
{
// When the CET is enabled, the return address is still on stack, so we need to set the Rsp as
// if it was popped.
hijackArgs.Rsp += 8;
}
hijackArgs.Rip = 0 ; // The OnHijackWorker sets this
#define CALLEE_SAVED_REGISTER(regname) hijackArgs.Regs.regname = pExceptionInfo->ContextRecord->regname;
ENUM_CALLEE_SAVED_REGISTERS();
#undef CALLEE_SAVED_REGISTER

OnHijackWorker(&hijackArgs);

#define CALLEE_SAVED_REGISTER(regname) pExceptionInfo->ContextRecord->regname = hijackArgs.Regs.regname;
ENUM_CALLEE_SAVED_REGISTERS();
#undef CALLEE_SAVED_REGISTER
pExceptionInfo->ContextRecord->Rax = hijackArgs.Rax;

if (areCetShadowStacksEnabled)
{
// The context refers to the return instruction
// Set the return address on the stack to the original one
*(size_t *)pExceptionInfo->ContextRecord->Rsp = hijackArgs.ReturnAddress;
}
else
{
// The context refers to the location after the return was processed
pExceptionInfo->ContextRecord->Rip = hijackArgs.ReturnAddress;
}

return EXCEPTION_CONTINUE_EXECUTION;
}
#endif

// We need to unhijack the thread here if it is not unhijacked already. On x86 systems,
// we do this in Thread::StackWalkFramesEx, but on amd64 systems we have the OS walk the
Expand Down
35 changes: 33 additions & 2 deletions src/coreclr/vm/threadsuspend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ CLREvent* ThreadSuspend::g_pGCSuspendEvent = NULL;

ThreadSuspend::SUSPEND_REASON ThreadSuspend::m_suspendReason;

#if defined(TARGET_WINDOWS) && defined(TARGET_AMD64)
void* ThreadSuspend::g_returnAddressHijackTarget = NULL;
#endif

// If you add any thread redirection function, make sure the debugger can 1) recognize the redirection
// function, and 2) retrieve the original CONTEXT. See code:Debugger.InitializeHijackFunctionAddress and
// code:DacDbiInterfaceImpl.RetrieveHijackedContext.
Expand Down Expand Up @@ -4678,7 +4682,17 @@ void Thread::HijackThread(ReturnKind returnKind, ExecutionState *esb)
CONTRACTL_END;

_ASSERTE(IsValidReturnKind(returnKind));

VOID *pvHijackAddr = reinterpret_cast<VOID *>(OnHijackTripThread);

#if defined(TARGET_WINDOWS) && defined(TARGET_AMD64)
void* returnAddressHijackTarget = ThreadSuspend::GetReturnAddressHijackTarget();
if (returnAddressHijackTarget != NULL)
{
pvHijackAddr = returnAddressHijackTarget;
}
#endif // TARGET_WINDOWS && TARGET_AMD64

#ifdef TARGET_X86
if (returnKind == RT_Float)
{
Expand Down Expand Up @@ -5975,9 +5989,26 @@ bool Thread::InjectActivation(ActivationReason reason)
// Initialize thread suspension support
void ThreadSuspend::Initialize()
{
#if defined(FEATURE_HIJACK) && defined(TARGET_UNIX)
#ifdef FEATURE_HIJACK
#if defined(TARGET_UNIX)
::PAL_SetActivationFunction(HandleSuspensionForInterruptedThread, CheckActivationSafePoint);
#endif
#elif defined(TARGET_WINDOWS) && defined(TARGET_AMD64)
// Only versions of Windows that have the special user mode APC have a correct implementation of the return address hijack handling
if (Thread::UseSpecialUserModeApc())
{
HMODULE hModNtdll = WszLoadLibrary(W("ntdll.dll"));
if (hModNtdll != NULL)
{
typedef ULONG_PTR (NTAPI *PFN_RtlGetReturnAddressHijackTarget)();
PFN_RtlGetReturnAddressHijackTarget pfnRtlGetReturnAddressHijackTarget = (PFN_RtlGetReturnAddressHijackTarget)GetProcAddress(hModNtdll, "RtlGetReturnAddressHijackTarget");
if (pfnRtlGetReturnAddressHijackTarget != NULL)
{
g_returnAddressHijackTarget = (void*)pfnRtlGetReturnAddressHijackTarget();
}
}
}
#endif // TARGET_WINDOWS && TARGET_AMD64
#endif // FEATURE_HIJACK
}

#ifdef _DEBUG
Expand Down
11 changes: 11 additions & 0 deletions src/coreclr/vm/threadsuspend.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ class ThreadSuspend
private:
static CLREvent * g_pGCSuspendEvent;

#if defined(TARGET_WINDOWS) && defined(TARGET_AMD64)
static void* g_returnAddressHijackTarget;
#endif // TARGET_WINDOWS && TARGET_AMD64

// This is true iff we're currently in the process of suspending threads. Once the
// threads have been suspended, this is false. This is set via an instance of
// SuspendRuntimeInProgressHolder placed in SuspendRuntime, SysStartSuspendForDebug,
Expand Down Expand Up @@ -247,6 +251,13 @@ class ThreadSuspend
return g_pSuspensionThread;
}

#if defined(TARGET_WINDOWS) && defined(TARGET_AMD64)
static void* GetReturnAddressHijackTarget()
{
return g_returnAddressHijackTarget;
}
#endif // TARGET_WINDOWS && TARGET_AMD64

private:
static LONG m_DebugWillSyncCount;
};
Expand Down