Skip to content

Arm64: [PAC-RET] Add Pointer Authentication support for Arm64 (Part 1/3: JIT)#127838

Open
SwapnilGaikwad wants to merge 3 commits intodotnet:mainfrom
SwapnilGaikwad:github-jit-pac
Open

Arm64: [PAC-RET] Add Pointer Authentication support for Arm64 (Part 1/3: JIT)#127838
SwapnilGaikwad wants to merge 3 commits intodotnet:mainfrom
SwapnilGaikwad:github-jit-pac

Conversation

@SwapnilGaikwad
Copy link
Copy Markdown
Contributor

@SwapnilGaikwad SwapnilGaikwad commented May 5, 2026

As suggested in comment, this PR covers subset of changes from #125436 related to the JIT.

This PR adds support for Pointer Authentication (PAC) on Arm64. Pointer Authentication (PAC) is an Armv8.3+ security feature designed to mitigate Return-Oriented Programming (ROP) attacks by cryptographically signing return addresses. While using PAC, we store a signed return address, instead of the plain address, on the stack and later authenticate it before returning from a function. It ensures control flow returns to the intended caller.

More details on PAC and its role in software security can be found (here).

  • The current implementation of PAC is turned off by default, but can be turned on by setting DOTNET_JitPacEnabled=1.
  • PAC protects link register (LR) by signing it in the prolog (using paciasp) before it is split, using the current SP as the modifier. It then authenticates the LR in the epilog (using autiasp) before the function returns. If the signature is invalid, the execution fails with SIGILL.
  • Changes are limited to JIT.

NOTE: This PR adds part of the changes for PAC support to simply review process as discussed here. However it cannot pass the tests without the remaining parts. Kindly take a look at the CI status of #125436 to ensure correctness.

…/3: JIT changes)

As suggested in [comment](dotnet#125436 (comment)), this PR covers subset of changes from dotnet#125436 related to the JIT.

This PR adds support for Pointer Authentication (PAC) on Arm64. Pointer Authentication (PAC) is an Armv8.3+ security feature designed to mitigate Return-Oriented Programming (ROP) attacks by cryptographically signing return addresses. While using PAC, we store a signed return address, instead of the plain address, on the stack and later authenticate it before returning from a function. It ensures control flow returns to the intended caller.

More details on PAC and its role in software security can be found ([here](https://llsoftsec.github.io/llsoftsecbook/#sec:pointer-authentication)).

- The current implementation of PAC is turned off by default, but can be turned on by setting DOTNET_JitPacEnabled=1.
- PAC protects link register (LR) by signing it in the prolog (using `paciasp`) before it is split, using the current SP as the modifier. It then authenticates the LR in the epilog (using `autiasp`) before the function returns. If the signature is invalid, the execution fails with `SIGILL`.
- Changes are limited to JIT.
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label May 5, 2026
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label May 5, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Comment thread src/coreclr/jit/unwindarm64.cpp Outdated
// Tier0 signed LR with the Tier0 caller SP before allocating its frame.
// Recreate that SP from the current Tier0 body SP so we can authenticate
// LR before the OSR prolog later re-signs it with the OSR SP via PACIASP.
genInstrWithConstant(INS_add, EA_PTRSIZE, REG_IP0, REG_SPBASE, patchpointInfo->TotalFrameSize(), REG_IP0,
Copy link
Copy Markdown
Contributor

@dhartglassMSFT dhartglassMSFT May 6, 2026

Choose a reason for hiding this comment

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

@AndyAyersMS FYI if we want a second set of eyes on the OSR change here

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit - anyway if you're in here again Swapnil I'd change "authenticate LR" to "authenticate and strip LR" even though the latter is still implied, reads a little clearer to me

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This looks good to me.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If I understand correctly the tier0 code will have signed LR with the SP as it is on entry, while the OSR method will now sign LR with the value of SP after the tier0 adjustment.

Would it make more sense to just skip signing in the OSR method and then authenticate after both SP adjustments have been done in the epilog?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It might be possible to avoid authenticating and re-signing with the help of phantom unwind code representing stack allocation. However, it deviates from the simple model to use signing SP from current frame. I'm happy to explore this possibility in the follow-up PR as the current one is getting trickier to maintain 🙂

Copy link
Copy Markdown
Member

@jakobbotsch jakobbotsch May 7, 2026

Choose a reason for hiding this comment

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

The OSR function inherits the frame from the tier0 function, it is part of its frame. What we have now effectively is making OSR functions deviate from all other functions since it is signing with an SP that points into the middle of its frame. I am ok with it, but you may want to make sure the OSR case is well tested.
Also we may want to eventually do some perf testing for runtime async since these prologs can be very hot for runtime async.

help of phantom unwind code representing stack allocation

I think we would emit a phantom pac_sign_lr code, before we emitted the phantom SP adjustment.

@SwapnilGaikwad SwapnilGaikwad changed the title Arm64: [PAC-RET] Add Pointer Authentication support for Arm64 (Part 1… Arm64: [PAC-RET] Add Pointer Authentication support for Arm64 (Part 1/3): JIT changes May 8, 2026
@SwapnilGaikwad
Copy link
Copy Markdown
Contributor Author

This PR uses parts of #127949. It would be great if we could get PAC encoding PR earlier.

@SwapnilGaikwad SwapnilGaikwad changed the title Arm64: [PAC-RET] Add Pointer Authentication support for Arm64 (Part 1/3): JIT changes Arm64: [PAC-RET] Add Pointer Authentication support for Arm64 (Part 1/3): JIT May 8, 2026
@SwapnilGaikwad SwapnilGaikwad changed the title Arm64: [PAC-RET] Add Pointer Authentication support for Arm64 (Part 1/3): JIT Arm64: [PAC-RET] Add Pointer Authentication support for Arm64 (Part 1/3: JIT) May 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants