Skip to content

Arm-64: Add initial support for PAC-RET #110472

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 78 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
33c53fa
Add auth-strip in prolog and epilog of jitted methods
SwapnilGaikwad Dec 6, 2024
c45b4a8
Merge main
SwapnilGaikwad Jan 24, 2025
19b977a
Use unwind info to indicate use of PAC
SwapnilGaikwad Jan 24, 2025
c2c03f9
Merge main
SwapnilGaikwad Jan 30, 2025
c64cc1f
Switch to auth with zero and fix tail call optimisations
SwapnilGaikwad Jan 30, 2025
cfddf71
fix nativeaot CFI unwind code
kunalspathak Jan 31, 2025
3bf9346
fix build
kunalspathak Jan 31, 2025
042210f
Add STRIP_PAC
kunalspathak Feb 5, 2025
435a901
wip
kunalspathak Feb 6, 2025
e9f101c
Uncomment the implementation of RtlStripPacOnline()
kunalspathak Feb 6, 2025
1dae16f
Add some missing declaration of CFI_NEGATE_RA_STATE
kunalspathak Feb 6, 2025
a1265fb
build fix
kunalspathak Feb 6, 2025
8a05d92
Comment StripOnline
kunalspathak Feb 6, 2025
98246b7
Add JitPacEnabled() switch
kunalspathak Feb 6, 2025
cb3879b
Make PacEnabled a Release flag
kunalspathak Feb 7, 2025
5a24d2a
Just strip from bit 48 onwards because thats what works for linux
kunalspathak Feb 7, 2025
ba343d2
Fix return address hijacking
SwapnilGaikwad Feb 13, 2025
e414fc7
Unwinder: Strip the Lr before storing in PC
kunalspathak Feb 17, 2025
f3b9e61
Emit pac unwind info in epilog
SwapnilGaikwad Feb 19, 2025
bb67312
Add inline assembly variants for MSVC
SwapnilGaikwad Feb 21, 2025
abfe3d4
Merge main
SwapnilGaikwad Feb 24, 2025
0d0fc7f
Remove MSVC assembly
SwapnilGaikwad Mar 3, 2025
8394024
Merge main
SwapnilGaikwad Mar 3, 2025
ddf6c3d
Restore previous fix to check its impact on nativeaot failures
SwapnilGaikwad Mar 12, 2025
2b6bf2b
Fix basic AOT tests
SwapnilGaikwad Mar 12, 2025
b408ec5
Fix reaturn address hijacking for AOT
SwapnilGaikwad Mar 12, 2025
a5a94a7
Merge main
SwapnilGaikwad Mar 13, 2025
240b551
Disable emitting authenticate to see behaviour on windows
SwapnilGaikwad Mar 18, 2025
09a6c40
Fix return address comparison for tail calls in native aot
SwapnilGaikwad Mar 18, 2025
1dcf083
Sign return address while restoring it in unhijacking a thread
SwapnilGaikwad Mar 18, 2025
618b79c
Merge main
SwapnilGaikwad Mar 19, 2025
25c7f72
Fix build errors
SwapnilGaikwad Mar 19, 2025
1e6b5b6
Fix build errors
SwapnilGaikwad Mar 19, 2025
6aebd8b
Fix build errors for casting
SwapnilGaikwad Mar 19, 2025
b230513
Fix build errors
SwapnilGaikwad Mar 19, 2025
b9802ed
Merge main
SwapnilGaikwad Mar 31, 2025
9c216f5
Put dwarf cfi code for pac
SwapnilGaikwad Apr 9, 2025
f5b6ffa
Add a placeholder for OSX ObjectWriter
SwapnilGaikwad Apr 10, 2025
57112e3
Merge main
SwapnilGaikwad Apr 13, 2025
7d92dae
Add DEF_CFA opcode for ilc
SwapnilGaikwad Apr 13, 2025
6ef4025
Fix formatting
SwapnilGaikwad Apr 13, 2025
03cde20
Merge main
SwapnilGaikwad Apr 16, 2025
beb7829
Merge main
SwapnilGaikwad Apr 17, 2025
8e1a725
Enable PAC for non-jitted code
SwapnilGaikwad Apr 17, 2025
fb3ab0e
Merge main
SwapnilGaikwad Apr 24, 2025
457dd89
Intial clean-up: use xpacia instead of a mask
SwapnilGaikwad Apr 24, 2025
a17e8ba
Merge main
SwapnilGaikwad Apr 28, 2025
268a895
Clean-up inline assembly
SwapnilGaikwad Apr 28, 2025
526b7c2
Remove PAC for non-jitted code, added using compile time flags
SwapnilGaikwad Apr 28, 2025
711d1fc
Fix windows build errors
SwapnilGaikwad Apr 28, 2025
a99f639
Fix build errors
SwapnilGaikwad Apr 28, 2025
eefb18b
Update strip/sign mechanism to use nop variants of PAC instructions
SwapnilGaikwad May 1, 2025
8e087f5
Merge main
SwapnilGaikwad May 1, 2025
a1298d7
Merge main
SwapnilGaikwad May 15, 2025
36f166e
Incorporate review comments
SwapnilGaikwad May 15, 2025
989ff17
Merge main
SwapnilGaikwad May 16, 2025
05f8731
Incorporate review comments
SwapnilGaikwad May 16, 2025
260a807
Merge main
SwapnilGaikwad May 19, 2025
526717a
Disable JitPacEnabled flag by default
SwapnilGaikwad May 19, 2025
2c81d43
Merge main
SwapnilGaikwad Jun 12, 2025
7b552e5
Use unwind info to detect if PAC is present for jitted code
SwapnilGaikwad Jun 12, 2025
f36e335
Fix assert failure for return address
SwapnilGaikwad Jun 12, 2025
a862791
Make IsPacPresent() Arm64 only
SwapnilGaikwad Jun 12, 2025
8f5b485
Fix build errors
SwapnilGaikwad Jun 12, 2025
e7bc0fa
Fix build errors
SwapnilGaikwad Jun 13, 2025
f53b929
Add a prototype of using unwind info to detect PAC
SwapnilGaikwad Jun 22, 2025
82b0709
Merge main
SwapnilGaikwad Jun 22, 2025
7e207a4
Merge main
SwapnilGaikwad Jun 27, 2025
52f63d8
Extract IsPacPresent() outside the undwinder.cpp
SwapnilGaikwad Jun 27, 2025
79a3fbc
Remove clrnt.h changes
SwapnilGaikwad Jun 29, 2025
e1ba37b
Address review comments
SwapnilGaikwad Jun 29, 2025
75316bc
Fix starting offset while unwinding dwarf info
SwapnilGaikwad Jul 2, 2025
c9f8bd1
Fix build failures of MacOS
SwapnilGaikwad Jul 2, 2025
b8574ab
Merge main
SwapnilGaikwad Jul 7, 2025
333b5b2
Fix SIGILL in NativeAOT during unwinding
SwapnilGaikwad Jul 7, 2025
cecc9f4
Fix segfaults in libraries tests
SwapnilGaikwad Jul 7, 2025
34401fb
Restore JIT's stack unwinding that was lost while restoring unwinder.cpp
SwapnilGaikwad Jul 7, 2025
0bc660e
Merge main
SwapnilGaikwad Jul 11, 2025
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: 9 additions & 0 deletions src/coreclr/debug/ee/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
#include "../../vm/methoditer.h"
#include "../../vm/tailcallhelp.h"

#if defined(TARGET_ARM64)
extern "C" void* PacStripPtr(void* ptr);
#endif // TARGET_ARM64

const char *GetTType( TraceType tt);

#define IsSingleStep(exception) ((exception) == EXCEPTION_SINGLE_STEP)
Expand Down Expand Up @@ -5829,6 +5833,11 @@ static bool IsTailCall(const BYTE * ip, ControllerStackInfo* info, TailCallFunct
TailCallTls* tls = GetThread()->GetTailCallTls();
LPVOID tailCallAwareRetAddr = tls->GetFrame()->TailCallAwareReturnAddress;

#if defined(TARGET_ARM64)
retAddr = PacStripPtr(retAddr);
tailCallAwareRetAddr = PacStripPtr(tailCallAwareRetAddr);
#endif // TARGET_ARM64

LOG((LF_CORDB,LL_INFO1000, "ITCTR: ret addr is %p, tailcall aware ret addr is %p\n",
retAddr, tailCallAwareRetAddr));

Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/inc/cfi.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ enum CFI_OPCODE
{
CFI_ADJUST_CFA_OFFSET, // Offset is adjusted relative to the current one.
CFI_DEF_CFA_REGISTER, // New register is used to compute CFA
CFI_REL_OFFSET // Register is saved at offset from the current CFA
CFI_REL_OFFSET, // Register is saved at offset from the current CFA
CFI_DEF_CFA, // Take address from register and add offset to it
CFI_NEGATE_RA_STATE, // Sign the return address in lr with paciaz
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment in DwarfCfiOpcode.cs refers to a pacibsp. Which one is correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

paciaz is a correct one for now. It would be updated once we support signing with SP.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the spec for DW_CFA_AARCH64_negate_ra_state opcode require specific signing or is it meant to support any type of signing?

In other words, are there any unwinders that will break when we use non-standard signing with this opcode?

Copy link
Contributor Author

@SwapnilGaikwad SwapnilGaikwad Jun 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. It's likely that an unwinder could break. I'll investigate this further. Preliminary look suggests unwinders such as gcc's unwinder reconises only unsinged or signing with SP modes.

};

struct CFI_CODE
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/inc/clrconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,7 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableArm64Rcpc, W("EnableArm64Rc
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableArm64Rcpc2, W("EnableArm64Rcpc2"), 1, "Allows Arm64 Rcpc2+ hardware intrinsics to be disabled")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableArm64Sve, W("EnableArm64Sve"), 1, "Allows Arm64 SVE hardware intrinsics to be disabled")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableArm64Sve2, W("EnableArm64Sve2"), 1, "Allows Arm64 SVE2 hardware intrinsics to be disabled")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitPacEnabled, W("JitPacEnabled"), 1, "Allows Arm64 Pointer Authentication (PAC) to be disabled")
#elif defined(TARGET_RISCV64)
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableRiscV64Zba, W("EnableRiscV64Zba"), 1, "Allows RiscV64 Zba hardware intrinsics to be disabled")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableRiscV64Zbb, W("EnableRiscV64Zbb"), 1, "Allows RiscV64 Zbb hardware intrinsics to be disabled")
Expand Down
6 changes: 5 additions & 1 deletion src/coreclr/inc/gcinfodecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ typedef void * OBJECTREF;

#ifndef __cgencpu_h__

#if defined(TARGET_ARM64)
extern "C" void* PacStripPtr(void* ptr);
#endif // TARGET_ARM64

inline void SetIP(T_CONTEXT* context, PCODE rip)
{
_ASSERTE(!"don't call this");
Expand Down Expand Up @@ -105,7 +109,7 @@ inline PCODE GetIP(T_CONTEXT* context)
#elif defined(TARGET_ARM)
return (PCODE)context->Pc;
#elif defined(TARGET_ARM64)
return (PCODE)context->Pc;
return (PCODE) PacStripPtr((void *)context->Pc);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll move these strip operations to the source while populating the context. These are temporarily added until we get all the CI issues fixed.

#elif defined(TARGET_LOONGARCH64)
return (PCODE)context->Pc;
#elif defined(TARGET_RISCV64)
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/codegenarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,8 @@ void CodeGen::genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog)
GetEmitter()->emitIns_R_R_I(INS_add, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, spAdjust);
compiler->unwindAllocStack(spAdjust);
}

GetEmitter()->emitPacInEpilog();
}

//------------------------------------------------------------------------
Expand Down Expand Up @@ -1342,6 +1344,7 @@ void CodeGen::genFuncletProlog(BasicBlock* block)
gcInfo.gcResetForBB();

compiler->unwindBegProlog();
GetEmitter()->emitPacInProlog();

regMaskTP maskSaveRegsFloat = genFuncletInfo.fiSaveRegs & RBM_ALLFLOAT;
regMaskTP maskSaveRegsInt = genFuncletInfo.fiSaveRegs & ~maskSaveRegsFloat;
Expand Down Expand Up @@ -1628,6 +1631,8 @@ void CodeGen::genFuncletEpilog()
}
}

GetEmitter()->emitPacInEpilog();

inst_RV(INS_ret, REG_LR, TYP_I_IMPL);
compiler->unwindReturn(REG_LR);

Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/jit/codegenarmarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4464,6 +4464,9 @@ void CodeGen::genPushCalleeSavedRegisters()
}
#endif // DEBUG

// Sign LR as part of Pointer Authentication (PAC) support
GetEmitter()->emitPacInProlog();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either in this PR or in a follow-up PR, you might want to consider moving the pac instructions closer to where we save lr on the stack instead of doing it at the top all the time. That way, you could also have a way to get the sp address where the lr was saved and then use that address to build up the original sp used to strip/auth the lr in runtime layer.

image

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, number of things will need to be redone to get SP signing in place.


// The frameType number is arbitrary, is defined below, and corresponds to one of the frame styles we
// generate based on various sizes.
int frameType = 0;
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -8818,6 +8818,7 @@ class Compiler
void unwindSaveRegPair(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]
void unwindSaveRegPairPreindexed(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]!
void unwindSaveNext(); // unwind code: save_next
void unwindPacSignLR(); // unwind code: pac_sign_lr
void unwindReturn(regNumber reg); // ret lr
#endif // defined(TARGET_ARM64)

Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/emit.h
Original file line number Diff line number Diff line change
Expand Up @@ -3237,6 +3237,11 @@ class emitter
instrDescAlign* emitNewInstrAlign();
#endif

#if defined(TARGET_ARM64)
void emitPacInProlog();
void emitPacInEpilog();
#endif

instrDesc* emitNewInstrSmall(emitAttr attr);
instrDesc* emitNewInstr(emitAttr attr = EA_4BYTE);
instrDesc* emitNewInstrSC(emitAttr attr, cnsval_ssize_t cns);
Expand Down
26 changes: 26 additions & 0 deletions src/coreclr/jit/emitarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1397,6 +1397,32 @@ static const char * const bRegNames[] =

// clang-format on

//------------------------------------------------------------------------
// emitPacInProlog: Sign LR as part of Pointer Authentication (PAC) support
//
void emitter::emitPacInProlog()
{
if (JitConfig.JitPacEnabled() == 0)
{
return;
}
emitIns(INS_paciaz);
emitComp->unwindPacSignLR();
}

//------------------------------------------------------------------------
// emitPacInEpilog: unsign LR as part of Pointer Authentication (PAC) support
//
void emitter::emitPacInEpilog()
{
if (JitConfig.JitPacEnabled() == 0)
{
return;
}
emitIns(INS_autiaz);
emitComp->unwindPacSignLR();
}

//------------------------------------------------------------------------
// emitRegName: Returns a general-purpose register name or SIMD and floating-point scalar register name.
//
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ CONFIG_STRING(JitInlineMethodsWithEHRange, "JitInlineMethodsWithEHRange")

CONFIG_INTEGER(JitLongAddress, "JitLongAddress", 0) // Force using the large pseudo instruction form for long address
CONFIG_INTEGER(JitMaxUncheckedOffset, "JitMaxUncheckedOffset", 8)
RELEASE_CONFIG_INTEGER(JitPacEnabled, "JitPacEnabled", 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a remainder to turn it off before merging.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving them enabled until CI is happy.


//
// MinOpts
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/jit/unwind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,11 @@ void Compiler::DumpCfiInfo(bool isHotCode,
assert(dwarfReg == DWARF_REG_ILLEGAL);
printf(" CodeOffset: 0x%02X Op: AdjustCfaOffset Offset:0x%X\n", codeOffset, offset);
break;
case CFI_NEGATE_RA_STATE:
assert(dwarfReg == DWARF_REG_ILLEGAL);
assert(offset == 0);
printf(" CodeOffset: 0x%02X Op: NegateRAState\n", codeOffset);
break;
default:
printf(" Unrecognized CFI_CODE: 0x%llX\n", *(UINT64*)pCode);
break;
Expand Down
33 changes: 33 additions & 0 deletions src/coreclr/jit/unwindarm64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,33 @@ void Compiler::unwindSaveNext()
pu->AddCode(0xE6);
}

void Compiler::unwindPacSignLR()
{
if (JitConfig.JitPacEnabled() == 0)
{
return;
}
#if defined(FEATURE_CFI_SUPPORT)
if (generateCFIUnwindCodes())
{
FuncInfoDsc* func = funCurrentFunc();
UNATIVE_OFFSET cbProlog = 0;
if (compGeneratingProlog)
{
cbProlog = unwindGetCurrentOffset(func);
}

// Maps to DW_CFA_AARCH64_negate_ra_state
createCfiCode(func, cbProlog, CFI_NEGATE_RA_STATE, DWARF_REG_ILLEGAL);

return;
}
#endif // FEATURE_CFI_SUPPORT

// pac_sign_lr: 11111100: sign the return address in lr with paciaz
funCurrentFunc()->uwi.AddCode(0xFC);
}

void Compiler::unwindReturn(regNumber reg)
{
// Nothing to do; we will always have at least one trailing "end" opcode in our padding.
Expand Down Expand Up @@ -1081,6 +1108,12 @@ void DumpUnwindInfo(Compiler* comp,

printf(" %02X save_next\n", b1);
}
else if (b1 == 0xFC)
{
// pac_sign_lr: 11111100 : sign the return address in lr with paciaz.

printf(" %02X pac_sign_lr\n", b1);
}
else
{
// Unknown / reserved unwind code
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/nativeaot/Runtime/ICodeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,11 @@ class ICodeManager

virtual bool IsUnwindable(PTR_VOID pvAddress) PURE_VIRTUAL

#ifdef TARGET_ARM64
virtual bool IsPacPresent(MethodInfo * pMethodInfo,
REGDISPLAY * pRegisterSet ) PURE_VIRTUAL
#endif

virtual bool GetReturnAddressHijackInfo(MethodInfo * pMethodInfo,
REGDISPLAY * pRegisterSet, // in
PTR_PTR_VOID * ppvRetAddrLocation // out
Expand Down
12 changes: 12 additions & 0 deletions src/coreclr/nativeaot/Runtime/StackFrameIterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ EXTERN_C CODE_LOCATION RhpRethrow2;
#define FAILFAST_OR_DAC_FAIL_UNCONDITIONALLY(msg) { ASSERT_UNCONDITIONALLY(msg); RhFailFast(); }
#endif

#if defined(TARGET_ARM64)
extern "C" void* PacStripPtr(void* ptr);
#endif // TARGET_ARM64

StackFrameIterator::StackFrameIterator(Thread * pThreadToWalk, PInvokeTransitionFrame* pInitialTransitionFrame)
{
STRESS_LOG0(LF_STACKWALK, LL_INFO10000, "----Init---- [ GC ]\n");
Expand Down Expand Up @@ -1786,7 +1790,11 @@ void StackFrameIterator::NextInternal()
// if the thread is safe to walk, it better not have a hijack in place.
ASSERT(!m_pThread->IsHijacked());

#if defined(TARGET_ARM64)
SetControlPC(PacStripPtr(dac_cast<PTR_VOID>(PCODEToPINSTR(m_RegDisplay.GetIP()))));
#else
SetControlPC(dac_cast<PTR_VOID>(PCODEToPINSTR(m_RegDisplay.GetIP())));
#endif // TARGET_ARM64

PTR_VOID collapsingTargetFrame = NULL;

Expand Down Expand Up @@ -2117,6 +2125,10 @@ void StackFrameIterator::CalculateCurrentMethodState()
return;
}

#if defined(TARGET_ARM64)
m_ControlPC = PacStripPtr(m_ControlPC);
#endif // TARGET_ARM64

// Assume that the caller is likely to be in the same module
if (m_pCodeManager == NULL || !m_pCodeManager->FindMethodInfo(m_ControlPC, &m_methodInfo))
{
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/nativeaot/Runtime/arm64/GcProbe.S
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
// Fix the stack by restoring the original return address
//
ldr lr, [x2, #OFFSETOF__Thread__m_pvHijackedReturnAddress]
xpaclri

//
// Clear hijack state
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/nativeaot/Runtime/arm64/GcProbe.asm
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ PROBE_FRAME_SIZE field 0
;; Fix the stack by restoring the original return address
;;
ldr lr, [x2, #OFFSETOF__Thread__m_pvHijackedReturnAddress]
DCD 0xD50320FF ;; xpaclri instruction in binary to avoid error while compiling with non-PAC enabled compilers

;;
;; Clear hijack state
Expand Down
26 changes: 26 additions & 0 deletions src/coreclr/nativeaot/Runtime/arm64/MiscStubs.S
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,29 @@

#include <unixasmmacros.inc>
#include "AsmOffsets.inc"

// void* PacStripPtr(void *);
// This function strips the pointer of PAC info that is passed as an agrument.
// To avoid failing on non-PAC enabled machines, we use xpaclri (instead of xpaci) which strips lr explicitly.
// Thus we move need to move input in lr, strip it and copy it back to the result register.
.arch_extension pauth
LEAF_ENTRY PacStripPtr, _TEXT
mov x9, lr
mov lr, x0
xpaclri
mov x0, lr
ret x9
LEAF_END PacStripPtr, _TEXT

// void* PacSignPtr(void *);
// This function sign the input pointer using zero as salt.
// To avoid failing on non-PAC enabled machines, we use paciaz (instead of paciza) which signs lr explicitly.
// Thus we need to move input in lr, sign it and then copy it back to the result register.
.arch_extension pauth
LEAF_ENTRY PacSignPtr, _TEXT
mov x9, lr
mov lr, x0
paciaz
mov x0, lr
ret x9
LEAF_END PacSignPtr, _TEXT
24 changes: 24 additions & 0 deletions src/coreclr/nativeaot/Runtime/arm64/MiscStubs.asm
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,28 @@

TEXTAREA

; void* PacStripPtr(void *);
; This function strips the pointer of PAC info that is passed as an agrument.
; To avoid failing on non-PAC enabled machines, we use xpaclri (instead of xpaci) which strips lr explicitly.
; Thus we move need to move input in lr, strip it and copy it back to the result register.
LEAF_ENTRY PacStripPtr
mov x9, lr
mov lr, x0
DCD 0xD50320FF ; xpaclri instruction in binary to avoid error while compiling with non-PAC enabled compilers
mov x0, lr
ret x9
LEAF_END PacStripPtr

; void* PacSignPtr(void *);
; This function sign the input pointer using zero as salt.
; To avoid failing on non-PAC enabled machines, we use paciaz (instead of paciza) which signs lr explicitly.
; Thus we need to move input in lr, sign it and then copy it back to the result register.
LEAF_ENTRY PacSignPtr
mov x9, lr
mov lr, x0
DCD 0xD503231F ; paciaz instruction in binary to avoid error while compiling with non-PAC enabled compilers
mov x0, lr
ret x9
LEAF_END PacSignPtr

end
21 changes: 20 additions & 1 deletion src/coreclr/nativeaot/Runtime/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ static Thread* g_RuntimeInitializingThread;

#endif //!DACCESS_COMPILE

#if defined(TARGET_ARM64)
extern "C" void* PacSignPtr(void* ptr);
extern "C" void* PacStripPtr(void* ptr);
#endif // TARGET_ARM64

ee_alloc_context::PerThreadRandom::PerThreadRandom()
{
minipal_xoshiro128pp_init(&random_state, (uint32_t)minipal_lowres_ticks());
Expand Down Expand Up @@ -809,8 +814,14 @@ void Thread::HijackReturnAddressWorker(StackFrameIterator* frameIterator, Hijack
CrossThreadUnhijack();

void* pvRetAddr = *ppvRetAddrLocation;

ASSERT(pvRetAddr != NULL);

#if defined(TARGET_ARM64)
ASSERT(StackFrameIterator::IsValidReturnAddress(PacStripPtr(pvRetAddr)));
#else
ASSERT(StackFrameIterator::IsValidReturnAddress(pvRetAddr));
#endif // TARGET_ARM64

m_ppvHijackedReturnAddressLocation = ppvRetAddrLocation;
m_pvHijackedReturnAddress = pvRetAddr;
Expand All @@ -820,7 +831,14 @@ void Thread::HijackReturnAddressWorker(StackFrameIterator* frameIterator, Hijack
frameIterator->GetRegisterSet()));
#endif

*ppvRetAddrLocation = (void*)pfnHijackFunction;
void* pvHijackedAddr = (void*)pfnHijackFunction;
#if defined(TARGET_ARM64)
if (frameIterator->GetCodeManager()->IsPacPresent(frameIterator->GetMethodInfo(), frameIterator->GetRegisterSet()))
{
pvHijackedAddr = PacSignPtr(pvHijackedAddr);
}
#endif // TARGET_ARM64
*ppvRetAddrLocation = pvHijackedAddr;

STRESS_LOG2(LF_STACKWALK, LL_INFO10000, "InternalHijack: TgtThread = %llx, IP = %p\n",
GetPalThreadIdForLogging(), frameIterator->GetRegisterSet()->GetIP());
Expand Down Expand Up @@ -948,6 +966,7 @@ void Thread::UnhijackWorker()

// Restore the original return address.
ASSERT(m_ppvHijackedReturnAddressLocation != NULL);

*m_ppvHijackedReturnAddressLocation = m_pvHijackedReturnAddress;

// Clear the hijack state.
Expand Down
Loading
Loading