Skip to content

Commit 9bff252

Browse files
authored
Port to 2.1 - Fix hijack for ARM/ARM64/x86 on Unix (dotnet#20116)
* Fix hijacking for ARM/ARM64/x86 on Unix We were not checking the case when we have interrupted a thread inside of a function epilog for other architectures than amd64. When such an interruption happens, GS cookie check in a stack walking has failed, since we are unable to decode GS cookie location when the IP is in epilog. This fix implements IsIPInEpilog for all architectures and makes the check unconditional.
1 parent de29c4d commit 9bff252

File tree

3 files changed

+41
-16
lines changed

3 files changed

+41
-16
lines changed

src/vm/excep.cpp

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7870,7 +7870,7 @@ BOOL IsIPInEE(void *ip)
78707870
}
78717871
}
78727872

7873-
#if defined(_TARGET_AMD64_) && defined(FEATURE_HIJACK)
7873+
#if defined(FEATURE_HIJACK) && (!defined(_TARGET_X86_) || defined(FEATURE_PAL))
78747874

78757875
// This function is used to check if the specified IP is in the prolog or not.
78767876
bool IsIPInProlog(EECodeInfo *pCodeInfo)
@@ -7887,6 +7887,9 @@ bool IsIPInProlog(EECodeInfo *pCodeInfo)
78877887

78887888
_ASSERTE(pCodeInfo->IsValid());
78897889

7890+
#ifdef _TARGET_AMD64_
7891+
7892+
// Optimized version for AMD64 that doesn't need to go through the GC info decoding
78907893
PTR_RUNTIME_FUNCTION funcEntry = pCodeInfo->GetFunctionEntry();
78917894

78927895
// We should always get a function entry for a managed method
@@ -7896,8 +7899,31 @@ bool IsIPInProlog(EECodeInfo *pCodeInfo)
78967899
PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(pCodeInfo->GetModuleBase() + funcEntry->UnwindData);
78977900

78987901
// Check if the specified IP is beyond the prolog or not.
7899-
DWORD dwPrologLen = pUnwindInfo->SizeOfProlog;
7900-
if (pCodeInfo->GetRelOffset() >= dwPrologLen)
7902+
DWORD prologLen = pUnwindInfo->SizeOfProlog;
7903+
7904+
#else // _TARGET_AMD64_
7905+
7906+
GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
7907+
7908+
#ifdef USE_GC_INFO_DECODER
7909+
7910+
GcInfoDecoder gcInfoDecoder(
7911+
gcInfoToken,
7912+
DECODE_PROLOG_LENGTH
7913+
);
7914+
7915+
DWORD prologLen = gcInfoDecoder.GetPrologSize();
7916+
7917+
#else // USE_GC_INFO_DECODER
7918+
7919+
size_t prologLen;
7920+
pCodeInfo->GetCodeManager()->IsInPrologOrEpilog(0, gcInfoToken, &prologLen);
7921+
7922+
#endif // USE_GC_INFO_DECODER
7923+
7924+
#endif // _TARGET_AMD64_
7925+
7926+
if (pCodeInfo->GetRelOffset() >= prologLen)
79017927
{
79027928
fInsideProlog = false;
79037929
}
@@ -7920,11 +7946,11 @@ bool IsIPInEpilog(PTR_CONTEXT pContextToCheck, EECodeInfo *pCodeInfo, BOOL *pSaf
79207946
CONTRACTL_END;
79217947

79227948
TADDR ipToCheck = GetIP(pContextToCheck);
7923-
7949+
79247950
_ASSERTE(pCodeInfo->IsValid());
7925-
7951+
79267952
// The Codeinfo should correspond to the IP we are interested in.
7927-
_ASSERTE(ipToCheck == pCodeInfo->GetCodeAddress());
7953+
_ASSERTE(PCODEToPINSTR(ipToCheck) == pCodeInfo->GetCodeAddress());
79287954

79297955
// By default, assume its safe to inject the abort.
79307956
*pSafeToInjectThreadAbort = TRUE;
@@ -7951,11 +7977,10 @@ bool IsIPInEpilog(PTR_CONTEXT pContextToCheck, EECodeInfo *pCodeInfo, BOOL *pSaf
79517977
// RtlVirtualUnwind against "ipToCheck" results in a NULL personality routine, it implies that we are inside
79527978
// the epilog.
79537979

7954-
DWORD64 imageBase = 0;
7955-
PUNWIND_INFO pUnwindInfo = NULL;
7980+
DWORD_PTR imageBase = 0;
79567981
CONTEXT tempContext;
79577982
PVOID HandlerData;
7958-
DWORD64 establisherFrame = 0;
7983+
DWORD_PTR establisherFrame = 0;
79597984
PEXCEPTION_ROUTINE personalityRoutine = NULL;
79607985

79617986
// Lookup the function entry for the IP
@@ -7965,7 +7990,6 @@ bool IsIPInEpilog(PTR_CONTEXT pContextToCheck, EECodeInfo *pCodeInfo, BOOL *pSaf
79657990
_ASSERTE(funcEntry != NULL);
79667991

79677992
imageBase = pCodeInfo->GetModuleBase();
7968-
pUnwindInfo = (PUNWIND_INFO)(imageBase+ funcEntry->UnwindData);
79697993

79707994
ZeroMemory(&tempContext, sizeof(CONTEXT));
79717995
CopyOSContext(&tempContext, pContextToCheck);
@@ -7988,13 +8012,15 @@ bool IsIPInEpilog(PTR_CONTEXT pContextToCheck, EECodeInfo *pCodeInfo, BOOL *pSaf
79888012
// We are in epilog.
79898013
fIsInEpilog = true;
79908014

8015+
#ifdef _TARGET_AMD64_
79918016
// Check if context pointers has returned the address of the stack location in the hijacked function
79928017
// from where RBP was restored. If the address is NULL, then it implies that RBP has been popped off.
79938018
// Since JIT64 ensures that pop of RBP is the last instruction before ret/jmp, it implies its not safe
79948019
// to inject an abort @ this point as EstablisherFrame (which will be based
79958020
// of RBP for managed code since that is the FramePointer register, as indicated in the UnwindInfo)
79968021
// will be off and can result in bad managed exception dispatch.
7997-
if (ctxPtrs.Rbp == NULL)
8022+
if (ctxPtrs.Rbp == NULL)
8023+
#endif
79988024
{
79998025
*pSafeToInjectThreadAbort = FALSE;
80008026
}
@@ -8003,7 +8029,7 @@ bool IsIPInEpilog(PTR_CONTEXT pContextToCheck, EECodeInfo *pCodeInfo, BOOL *pSaf
80038029
return fIsInEpilog;
80048030
}
80058031

8006-
#endif // defined(_TARGET_AMD64_) && defined(FEATURE_HIJACK)
8032+
#endif // FEATURE_HIJACK && (!_TARGET_X86_ || FEATURE_PAL)
80078033

80088034
#define EXCEPTION_VISUALCPP_DEBUGGER ((DWORD) (1<<30 | 0x6D<<16 | 5000))
80098035

src/vm/excep.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ class Thread;
2525
BOOL IsExceptionFromManagedCode(const EXCEPTION_RECORD * pExceptionRecord);
2626
bool IsIPInMarkedJitHelper(UINT_PTR uControlPc);
2727

28-
#if defined(_TARGET_AMD64_) && defined(FEATURE_HIJACK)
28+
#if defined(FEATURE_HIJACK) && (!defined(_TARGET_X86_) || defined(FEATURE_PAL))
2929

3030
// General purpose functions for use on an IP in jitted code.
3131
bool IsIPInProlog(EECodeInfo *pCodeInfo);
3232
bool IsIPInEpilog(PTR_CONTEXT pContextToCheck, EECodeInfo *pCodeInfo, BOOL *pSafeToInjectThreadAbort);
3333

34-
#endif // defined(_TARGET_AMD64_) && defined(FEATURE_HIJACK)
34+
#endif // FEATURE_HIJACK && (!_TARGET_X86_ || FEATURE_PAL)
3535

3636
void RaiseFailFastExceptionOnWin7(PEXCEPTION_RECORD pExceptionRecord, PT_CONTEXT pContext);
3737

src/vm/threadsuspend.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7467,10 +7467,9 @@ void HandleGCSuspensionForInterruptedThread(CONTEXT *interruptedContext)
74677467
pThread->InitRegDisplay(&regDisplay, interruptedContext, true /* validContext */);
74687468

74697469
BOOL unused;
7470-
#if defined(_TARGET_AMD64_)
7470+
74717471
if (IsIPInEpilog(interruptedContext, &codeInfo, &unused))
74727472
return;
7473-
#endif
74747473

74757474
// Use StackWalkFramesEx to find the location of the return address. This will locate the
74767475
// return address by checking relative to the caller frame's SP, which is preferable to

0 commit comments

Comments
 (0)